Add a 1x1 cell widget
Larger sizes are to come
This commit is contained in:
parent
21d5fafa74
commit
dc0639784e
@ -15,6 +15,12 @@
|
|||||||
<category android:name="android.intent.category.LAUNCHER" />
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
|
<receiver android:name=".OneCellWidget" android:label="Vanilla Music 1x1">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
|
||||||
|
</intent-filter>
|
||||||
|
<meta-data android:name="android.appwidget.provider" android:resource="@xml/one_cell_widget" />
|
||||||
|
</receiver>
|
||||||
<activity
|
<activity
|
||||||
android:name="RemoteActivity"
|
android:name="RemoteActivity"
|
||||||
android:theme="@android:style/Theme.Dialog"
|
android:theme="@android:style/Theme.Dialog"
|
||||||
|
BIN
res/drawable/empty.png
Normal file
BIN
res/drawable/empty.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 163 B |
10
res/drawable/hidden_next.xml
Normal file
10
res/drawable/hidden_next.xml
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<item
|
||||||
|
android:state_pressed="true"
|
||||||
|
android:drawable="@drawable/next_normal" />
|
||||||
|
<item
|
||||||
|
android:state_focused="true"
|
||||||
|
android:drawable="@drawable/next_normal" />
|
||||||
|
<item android:drawable="@drawable/empty" />
|
||||||
|
</selector>
|
10
res/drawable/hidden_play_pause.xml
Normal file
10
res/drawable/hidden_play_pause.xml
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<item
|
||||||
|
android:state_pressed="true"
|
||||||
|
android:drawable="@drawable/pause_normal" />
|
||||||
|
<item
|
||||||
|
android:state_focused="true"
|
||||||
|
android:drawable="@drawable/pause_normal" />
|
||||||
|
<item android:drawable="@drawable/empty" />
|
||||||
|
</selector>
|
8
res/layout/default_widget.xml
Normal file
8
res/layout/default_widget.xml
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<TextView
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:id="@+id/stopped_text"
|
||||||
|
android:layout_height="fill_parent"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:gravity="center"
|
||||||
|
android:text="Service stopped." />
|
27
res/layout/one_cell_widget.xml
Normal file
27
res/layout/one_cell_widget.xml
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<RelativeLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_height="fill_parent"
|
||||||
|
android:layout_width="fill_parent">
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/cover_view"
|
||||||
|
android:layout_height="fill_parent"
|
||||||
|
android:layout_width="fill_parent" />
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_height="fill_parent"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:orientation="vertical" >
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/play_pause"
|
||||||
|
android:background="@drawable/hidden_play_pause"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_weight="1" />
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/next"
|
||||||
|
android:background="@drawable/hidden_next"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_weight="1" />
|
||||||
|
</LinearLayout>
|
||||||
|
</RelativeLayout>
|
6
res/xml/one_cell_widget.xml
Normal file
6
res/xml/one_cell_widget.xml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<appwidget-provider
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:minWidth="72dip"
|
||||||
|
android:minHeight="72dip"
|
||||||
|
android:initialLayout="@layout/default_widget"
|
||||||
|
/>
|
@ -72,14 +72,14 @@ public class CoverView extends View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void drawText(Canvas canvas, String text, float left, float top, float width, float maxWidth, Paint paint)
|
private static void drawText(Canvas canvas, String text, float left, float top, float width, float maxWidth, Paint paint)
|
||||||
{
|
{
|
||||||
float offset = Math.max(0, maxWidth - width) / 2;
|
float offset = Math.max(0, maxWidth - width) / 2;
|
||||||
canvas.clipRect(left, top, left + maxWidth, top + paint.getTextSize() * 2, Region.Op.REPLACE);
|
canvas.clipRect(left, top, left + maxWidth, top + paint.getTextSize() * 2, Region.Op.REPLACE);
|
||||||
canvas.drawText(text, left + offset, top - paint.ascent(), paint);
|
canvas.drawText(text, left + offset, top - paint.ascent(), paint);
|
||||||
}
|
}
|
||||||
|
|
||||||
private RectF centerRect(float maxWidth, float maxHeight, float width, float height)
|
private static RectF centerRect(float maxWidth, float maxHeight, float width, float height)
|
||||||
{
|
{
|
||||||
RectF rect = new RectF();
|
RectF rect = new RectF();
|
||||||
rect.left = (maxWidth - width) / 2;
|
rect.left = (maxWidth - width) / 2;
|
||||||
@ -89,17 +89,65 @@ public class CoverView extends View {
|
|||||||
return rect;
|
return rect;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void createBitmap(int i)
|
private static RectF bottomStretchRect(float maxWidth, float maxHeight, float width, float height)
|
||||||
{
|
{
|
||||||
Song song = mSongs[i];
|
RectF rect = new RectF();
|
||||||
Bitmap bitmap = null;
|
rect.left = 0;
|
||||||
|
rect.top = maxHeight - height;
|
||||||
|
rect.right = maxWidth;
|
||||||
|
rect.bottom = maxHeight;
|
||||||
|
return rect;
|
||||||
|
}
|
||||||
|
|
||||||
if (song != null) {
|
public static Bitmap createMiniBitmap(Song song, int width, int height)
|
||||||
int width = getWidth();
|
{
|
||||||
int height = getHeight();
|
if (song == null || width < 1 || height < 1)
|
||||||
|
return null;
|
||||||
|
|
||||||
if (width == 0 || height == 0)
|
Paint paint = new Paint();
|
||||||
return;
|
paint.setAntiAlias(true);
|
||||||
|
|
||||||
|
String title = song.title == null ? "" : song.title;
|
||||||
|
Bitmap cover = song.coverPath == null ? null : BitmapFactory.decodeFile(song.coverPath);
|
||||||
|
|
||||||
|
float titleSize = 12;
|
||||||
|
float padding = 2;
|
||||||
|
|
||||||
|
paint.setTextSize(titleSize);
|
||||||
|
float titleWidth = paint.measureText(title);
|
||||||
|
|
||||||
|
float boxWidth = width;
|
||||||
|
float boxHeight = Math.min(height, titleSize + padding * 2);
|
||||||
|
|
||||||
|
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
|
||||||
|
Canvas canvas = new Canvas(bitmap);
|
||||||
|
|
||||||
|
if (cover != null) {
|
||||||
|
canvas.drawBitmap(cover, null, new Rect(0, 0, width, height), paint);
|
||||||
|
cover.recycle();
|
||||||
|
cover = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
RectF boxRect = bottomStretchRect(width, height, boxWidth, boxHeight);
|
||||||
|
|
||||||
|
paint.setARGB(150, 0, 0, 0);
|
||||||
|
canvas.drawRect(boxRect, paint);
|
||||||
|
|
||||||
|
float maxWidth = boxWidth - padding * 2;
|
||||||
|
paint.setARGB(255, 255, 255, 255);
|
||||||
|
boxRect.top += padding;
|
||||||
|
boxRect.left += padding;
|
||||||
|
|
||||||
|
paint.setTextSize(titleSize);
|
||||||
|
drawText(canvas, title, boxRect.left, boxRect.top, titleWidth, maxWidth, paint);
|
||||||
|
|
||||||
|
return bitmap;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Bitmap createBitmap(Song song, int width, int height)
|
||||||
|
{
|
||||||
|
if (song == null || width < 1 || height < 1)
|
||||||
|
return null;
|
||||||
|
|
||||||
Paint paint = new Paint();
|
Paint paint = new Paint();
|
||||||
paint.setAntiAlias(true);
|
paint.setAntiAlias(true);
|
||||||
@ -144,7 +192,7 @@ public class CoverView extends View {
|
|||||||
int bitmapWidth = (int)Math.max(coverWidth, boxWidth);
|
int bitmapWidth = (int)Math.max(coverWidth, boxWidth);
|
||||||
int bitmapHeight = (int)Math.max(coverHeight, boxHeight);
|
int bitmapHeight = (int)Math.max(coverHeight, boxHeight);
|
||||||
|
|
||||||
bitmap = Bitmap.createBitmap(bitmapWidth, bitmapHeight, Bitmap.Config.RGB_565);
|
Bitmap bitmap = Bitmap.createBitmap(bitmapWidth, bitmapHeight, Bitmap.Config.RGB_565);
|
||||||
Canvas canvas = new Canvas(bitmap);
|
Canvas canvas = new Canvas(bitmap);
|
||||||
|
|
||||||
if (cover != null) {
|
if (cover != null) {
|
||||||
@ -173,10 +221,14 @@ public class CoverView extends View {
|
|||||||
boxRect.top += subSize + padding;
|
boxRect.top += subSize + padding;
|
||||||
|
|
||||||
drawText(canvas, artist, boxRect.left, boxRect.top, artistWidth, maxWidth, paint);
|
drawText(canvas, artist, boxRect.left, boxRect.top, artistWidth, maxWidth, paint);
|
||||||
|
|
||||||
|
return bitmap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void createBitmap(int i)
|
||||||
|
{
|
||||||
Bitmap oldBitmap = mBitmaps[i];
|
Bitmap oldBitmap = mBitmaps[i];
|
||||||
mBitmaps[i] = bitmap;
|
mBitmaps[i] = createBitmap(mSongs[i], getWidth(), getHeight());
|
||||||
if (oldBitmap != null)
|
if (oldBitmap != null)
|
||||||
oldBitmap.recycle();
|
oldBitmap.recycle();
|
||||||
}
|
}
|
||||||
|
41
src/org/kreed/vanilla/OneCellWidget.java
Normal file
41
src/org/kreed/vanilla/OneCellWidget.java
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
package org.kreed.vanilla;
|
||||||
|
|
||||||
|
import android.app.PendingIntent;
|
||||||
|
import android.appwidget.AppWidgetManager;
|
||||||
|
import android.appwidget.AppWidgetProvider;
|
||||||
|
import android.content.ComponentName;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.widget.RemoteViews;
|
||||||
|
|
||||||
|
public class OneCellWidget extends AppWidgetProvider {
|
||||||
|
@Override
|
||||||
|
public void onUpdate(Context context, AppWidgetManager manager, int[] ids)
|
||||||
|
{
|
||||||
|
context.sendBroadcast(new Intent(PlaybackService.APPWIDGET_SMALL_UPDATE));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void sendUpdate(Context context, RemoteViews views)
|
||||||
|
{
|
||||||
|
AppWidgetManager manager = AppWidgetManager.getInstance(context);
|
||||||
|
ComponentName widget = new ComponentName(context, OneCellWidget.class);
|
||||||
|
manager.updateAppWidget(widget, views);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void update(Context context, Song song)
|
||||||
|
{
|
||||||
|
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.one_cell_widget);
|
||||||
|
views.setOnClickPendingIntent(R.id.play_pause, PendingIntent.getBroadcast(context, 0, new Intent(PlaybackService.TOGGLE_PLAYBACK), 0));
|
||||||
|
views.setOnClickPendingIntent(R.id.next, PendingIntent.getBroadcast(context, 0, new Intent(PlaybackService.NEXT_SONG), 0));
|
||||||
|
if (song != null)
|
||||||
|
views.setImageViewBitmap(R.id.cover_view, CoverView.createMiniBitmap(song, 72, 72));
|
||||||
|
|
||||||
|
sendUpdate(context, views);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void reset(Context context)
|
||||||
|
{
|
||||||
|
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.default_widget);
|
||||||
|
sendUpdate(context, views);
|
||||||
|
}
|
||||||
|
}
|
@ -56,6 +56,10 @@ import android.widget.Toast;
|
|||||||
public class PlaybackService extends Service implements Runnable, MediaPlayer.OnCompletionListener, MediaPlayer.OnErrorListener, SharedPreferences.OnSharedPreferenceChangeListener {
|
public class PlaybackService extends Service implements Runnable, MediaPlayer.OnCompletionListener, MediaPlayer.OnErrorListener, SharedPreferences.OnSharedPreferenceChangeListener {
|
||||||
private static final int NOTIFICATION_ID = 2;
|
private static final int NOTIFICATION_ID = 2;
|
||||||
|
|
||||||
|
public static final String APPWIDGET_SMALL_UPDATE = "org.kreed.vanilla.action.APPWIDGET_SMALL_UPDATE";
|
||||||
|
public static final String TOGGLE_PLAYBACK = "org.kreed.vanilla.action.TOGGLE_PLAYBACK";
|
||||||
|
public static final String NEXT_SONG = "org.kreed.vanilla.action.NEXT_SONG";
|
||||||
|
|
||||||
public static final int STATE_NORMAL = 0;
|
public static final int STATE_NORMAL = 0;
|
||||||
public static final int STATE_NO_MEDIA = 1;
|
public static final int STATE_NO_MEDIA = 1;
|
||||||
public static final int STATE_PLAYING = 2;
|
public static final int STATE_PLAYING = 2;
|
||||||
@ -187,6 +191,8 @@ public class PlaybackService extends Service implements Runnable, MediaPlayer.On
|
|||||||
unregisterReceiver(mReceiver);
|
unregisterReceiver(mReceiver);
|
||||||
mNotificationManager.cancel(NOTIFICATION_ID);
|
mNotificationManager.cancel(NOTIFICATION_ID);
|
||||||
|
|
||||||
|
resetWidgets();
|
||||||
|
|
||||||
if (mWakeLock != null && mWakeLock.isHeld())
|
if (mWakeLock != null && mWakeLock.isHeld())
|
||||||
mWakeLock.release();
|
mWakeLock.release();
|
||||||
}
|
}
|
||||||
@ -235,6 +241,27 @@ public class PlaybackService extends Service implements Runnable, MediaPlayer.On
|
|||||||
} else if (Intent.ACTION_MEDIA_SCANNER_FINISHED.equals(action)
|
} else if (Intent.ACTION_MEDIA_SCANNER_FINISHED.equals(action)
|
||||||
|| Intent.ACTION_MEDIA_SCANNER_SCAN_FILE.equals(action)) {
|
|| Intent.ACTION_MEDIA_SCANNER_SCAN_FILE.equals(action)) {
|
||||||
mHandler.sendEmptyMessage(RETRIEVE_SONGS);
|
mHandler.sendEmptyMessage(RETRIEVE_SONGS);
|
||||||
|
} else if (TOGGLE_PLAYBACK.equals(action)) {
|
||||||
|
if (mHandler.hasMessages(DO)) {
|
||||||
|
mHandler.removeMessages(DO);
|
||||||
|
Intent launcher = new Intent(PlaybackService.this, NowPlayingActivity.class);
|
||||||
|
launcher.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||||
|
startActivity(launcher);
|
||||||
|
} else {
|
||||||
|
mHandler.sendMessageDelayed(mHandler.obtainMessage(DO, PLAY_PAUSE, 0), 250);
|
||||||
|
}
|
||||||
|
} else if (NEXT_SONG.equals(action)) {
|
||||||
|
if (mHandler.hasMessages(DO)) {
|
||||||
|
mHandler.removeMessages(DO);
|
||||||
|
Intent launcher = new Intent(PlaybackService.this, NowPlayingActivity.class);
|
||||||
|
launcher.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||||
|
startActivity(launcher);
|
||||||
|
} else {
|
||||||
|
mHandler.sendMessageDelayed(mHandler.obtainMessage(DO, SET_SONG, 1), 250);
|
||||||
|
}
|
||||||
|
} else if (APPWIDGET_SMALL_UPDATE.equals(intent.getAction())) {
|
||||||
|
OneCellWidget.update(PlaybackService.this, getSong(0));
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -297,6 +324,7 @@ public class PlaybackService extends Service implements Runnable, MediaPlayer.On
|
|||||||
private static final int HANDLE_PAUSE = 8;
|
private static final int HANDLE_PAUSE = 8;
|
||||||
private static final int RETRIEVE_SONGS = 9;
|
private static final int RETRIEVE_SONGS = 9;
|
||||||
private static final int CALL = 10;
|
private static final int CALL = 10;
|
||||||
|
private static final int DO = 11;
|
||||||
|
|
||||||
public void run()
|
public void run()
|
||||||
{
|
{
|
||||||
@ -376,6 +404,16 @@ public class PlaybackService extends Service implements Runnable, MediaPlayer.On
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case DO:
|
||||||
|
if (message.arg1 == DO) {
|
||||||
|
Log.w("VanillaMusic", "handleMessage.DO should not be called with arg1 = DO");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
message.what = message.arg1;
|
||||||
|
message.arg1 = message.arg2;
|
||||||
|
handleMessage(message);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -384,6 +422,9 @@ public class PlaybackService extends Service implements Runnable, MediaPlayer.On
|
|||||||
filter.addAction(Intent.ACTION_HEADSET_PLUG);
|
filter.addAction(Intent.ACTION_HEADSET_PLUG);
|
||||||
filter.addAction(Intent.ACTION_MEDIA_SCANNER_FINISHED);
|
filter.addAction(Intent.ACTION_MEDIA_SCANNER_FINISHED);
|
||||||
filter.addAction(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
|
filter.addAction(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
|
||||||
|
filter.addAction(TOGGLE_PLAYBACK);
|
||||||
|
filter.addAction(NEXT_SONG);
|
||||||
|
filter.addAction(APPWIDGET_SMALL_UPDATE);
|
||||||
registerReceiver(mReceiver, filter);
|
registerReceiver(mReceiver, filter);
|
||||||
|
|
||||||
PowerManager powerManager = (PowerManager)getSystemService(POWER_SERVICE);
|
PowerManager powerManager = (PowerManager)getSystemService(POWER_SERVICE);
|
||||||
@ -554,6 +595,8 @@ public class PlaybackService extends Service implements Runnable, MediaPlayer.On
|
|||||||
mSongTimeline.remove(0);
|
mSongTimeline.remove(0);
|
||||||
--mCurrentSong;
|
--mCurrentSong;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updateWidgets();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onCompletion(MediaPlayer player)
|
public void onCompletion(MediaPlayer player)
|
||||||
@ -598,4 +641,15 @@ public class PlaybackService extends Service implements Runnable, MediaPlayer.On
|
|||||||
|
|
||||||
return mSongTimeline.get(pos);
|
return mSongTimeline.get(pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void updateWidgets()
|
||||||
|
{
|
||||||
|
Song song = getSong(0);
|
||||||
|
OneCellWidget.update(this, song);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void resetWidgets()
|
||||||
|
{
|
||||||
|
OneCellWidget.reset(this);
|
||||||
|
}
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user