diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 4b08c87f..67509bed 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -15,6 +15,12 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/res/drawable/hidden_play_pause.xml b/res/drawable/hidden_play_pause.xml
new file mode 100644
index 00000000..1493033e
--- /dev/null
+++ b/res/drawable/hidden_play_pause.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/res/layout/default_widget.xml b/res/layout/default_widget.xml
new file mode 100644
index 00000000..adb3b044
--- /dev/null
+++ b/res/layout/default_widget.xml
@@ -0,0 +1,8 @@
+
+
\ No newline at end of file
diff --git a/res/layout/one_cell_widget.xml b/res/layout/one_cell_widget.xml
new file mode 100644
index 00000000..2a6f3eb6
--- /dev/null
+++ b/res/layout/one_cell_widget.xml
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/res/xml/one_cell_widget.xml b/res/xml/one_cell_widget.xml
new file mode 100644
index 00000000..6a7990b0
--- /dev/null
+++ b/res/xml/one_cell_widget.xml
@@ -0,0 +1,6 @@
+
\ No newline at end of file
diff --git a/src/org/kreed/vanilla/CoverView.java b/src/org/kreed/vanilla/CoverView.java
index 4bd18b62..a1ae833a 100644
--- a/src/org/kreed/vanilla/CoverView.java
+++ b/src/org/kreed/vanilla/CoverView.java
@@ -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;
canvas.clipRect(left, top, left + maxWidth, top + paint.getTextSize() * 2, Region.Op.REPLACE);
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();
rect.left = (maxWidth - width) / 2;
@@ -89,94 +89,146 @@ public class CoverView extends View {
return rect;
}
+ private static RectF bottomStretchRect(float maxWidth, float maxHeight, float width, float height)
+ {
+ RectF rect = new RectF();
+ rect.left = 0;
+ rect.top = maxHeight - height;
+ rect.right = maxWidth;
+ rect.bottom = maxHeight;
+ return rect;
+ }
+
+ public static Bitmap createMiniBitmap(Song song, int width, int height)
+ {
+ if (song == null || width < 1 || height < 1)
+ return null;
+
+ Paint paint = new Paint();
+ 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.setAntiAlias(true);
+
+ String title = song.title == null ? "" : song.title;
+ String album = song.album == null ? "" : song.album;
+ String artist = song.artist == null ? "" : song.artist;
+ Bitmap cover = song.coverPath == null ? null : BitmapFactory.decodeFile(song.coverPath);
+
+ float titleSize = 20;
+ float subSize = 14;
+ float padding = 10;
+
+ paint.setTextSize(titleSize);
+ float titleWidth = paint.measureText(title);
+ paint.setTextSize(subSize);
+ float albumWidth = paint.measureText(album);
+ float artistWidth = paint.measureText(artist);
+
+ float boxWidth = Math.min(width, Math.max(titleWidth, Math.max(artistWidth, albumWidth)) + padding * 2);
+ float boxHeight = Math.min(height, titleSize + subSize * 2 + padding * 4);
+
+ float coverWidth;
+ float coverHeight;
+
+ if (cover == null) {
+ coverWidth = 0;
+ coverHeight = 0;
+ } else {
+ coverWidth = cover.getWidth();
+ coverHeight = cover.getHeight();
+
+ float drawableAspectRatio = coverHeight / coverWidth;
+ float viewAspectRatio = (float) height / width;
+ float scale = drawableAspectRatio > viewAspectRatio ? height / coverWidth
+ : width / coverHeight;
+
+ coverWidth *= scale;
+ coverHeight *= scale;
+ }
+
+ int bitmapWidth = (int)Math.max(coverWidth, boxWidth);
+ int bitmapHeight = (int)Math.max(coverHeight, boxHeight);
+
+ Bitmap bitmap = Bitmap.createBitmap(bitmapWidth, bitmapHeight, Bitmap.Config.RGB_565);
+ Canvas canvas = new Canvas(bitmap);
+
+ if (cover != null) {
+ RectF rect = centerRect(bitmapWidth, bitmapHeight, coverWidth, coverHeight);
+ canvas.drawBitmap(cover, null, rect, paint);
+ cover.recycle();
+ cover = null;
+ }
+
+ RectF boxRect = centerRect(bitmapWidth, bitmapHeight, 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);
+ boxRect.top += titleSize + padding;
+
+ paint.setTextSize(subSize);
+ drawText(canvas, album, boxRect.left, boxRect.top, albumWidth, maxWidth, paint);
+ boxRect.top += subSize + padding;
+
+ drawText(canvas, artist, boxRect.left, boxRect.top, artistWidth, maxWidth, paint);
+
+ return bitmap;
+ }
+
private void createBitmap(int i)
{
- Song song = mSongs[i];
- Bitmap bitmap = null;
-
- if (song != null) {
- int width = getWidth();
- int height = getHeight();
-
- if (width == 0 || height == 0)
- return;
-
- Paint paint = new Paint();
- paint.setAntiAlias(true);
-
- String title = song.title == null ? "" : song.title;
- String album = song.album == null ? "" : song.album;
- String artist = song.artist == null ? "" : song.artist;
- Bitmap cover = song.coverPath == null ? null : BitmapFactory.decodeFile(song.coverPath);
-
- float titleSize = 20;
- float subSize = 14;
- float padding = 10;
-
- paint.setTextSize(titleSize);
- float titleWidth = paint.measureText(title);
- paint.setTextSize(subSize);
- float albumWidth = paint.measureText(album);
- float artistWidth = paint.measureText(artist);
-
- float boxWidth = Math.min(width, Math.max(titleWidth, Math.max(artistWidth, albumWidth)) + padding * 2);
- float boxHeight = Math.min(height, titleSize + subSize * 2 + padding * 4);
-
- float coverWidth;
- float coverHeight;
-
- if (cover == null) {
- coverWidth = 0;
- coverHeight = 0;
- } else {
- coverWidth = cover.getWidth();
- coverHeight = cover.getHeight();
-
- float drawableAspectRatio = coverHeight / coverWidth;
- float viewAspectRatio = (float) height / width;
- float scale = drawableAspectRatio > viewAspectRatio ? height / coverWidth
- : width / coverHeight;
-
- coverWidth *= scale;
- coverHeight *= scale;
- }
-
- int bitmapWidth = (int)Math.max(coverWidth, boxWidth);
- int bitmapHeight = (int)Math.max(coverHeight, boxHeight);
-
- bitmap = Bitmap.createBitmap(bitmapWidth, bitmapHeight, Bitmap.Config.RGB_565);
- Canvas canvas = new Canvas(bitmap);
-
- if (cover != null) {
- RectF rect = centerRect(bitmapWidth, bitmapHeight, coverWidth, coverHeight);
- canvas.drawBitmap(cover, null, rect, paint);
- cover.recycle();
- cover = null;
- }
-
- RectF boxRect = centerRect(bitmapWidth, bitmapHeight, 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);
- boxRect.top += titleSize + padding;
-
- paint.setTextSize(subSize);
- drawText(canvas, album, boxRect.left, boxRect.top, albumWidth, maxWidth, paint);
- boxRect.top += subSize + padding;
-
- drawText(canvas, artist, boxRect.left, boxRect.top, artistWidth, maxWidth, paint);
- }
-
Bitmap oldBitmap = mBitmaps[i];
- mBitmaps[i] = bitmap;
+ mBitmaps[i] = createBitmap(mSongs[i], getWidth(), getHeight());
if (oldBitmap != null)
oldBitmap.recycle();
}
diff --git a/src/org/kreed/vanilla/OneCellWidget.java b/src/org/kreed/vanilla/OneCellWidget.java
new file mode 100644
index 00000000..a249ad97
--- /dev/null
+++ b/src/org/kreed/vanilla/OneCellWidget.java
@@ -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);
+ }
+}
\ No newline at end of file
diff --git a/src/org/kreed/vanilla/PlaybackService.java b/src/org/kreed/vanilla/PlaybackService.java
index 5e369ff1..a6af4ce5 100644
--- a/src/org/kreed/vanilla/PlaybackService.java
+++ b/src/org/kreed/vanilla/PlaybackService.java
@@ -56,6 +56,10 @@ import android.widget.Toast;
public class PlaybackService extends Service implements Runnable, MediaPlayer.OnCompletionListener, MediaPlayer.OnErrorListener, SharedPreferences.OnSharedPreferenceChangeListener {
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_NO_MEDIA = 1;
public static final int STATE_PLAYING = 2;
@@ -187,6 +191,8 @@ public class PlaybackService extends Service implements Runnable, MediaPlayer.On
unregisterReceiver(mReceiver);
mNotificationManager.cancel(NOTIFICATION_ID);
+ resetWidgets();
+
if (mWakeLock != null && mWakeLock.isHeld())
mWakeLock.release();
}
@@ -235,6 +241,27 @@ public class PlaybackService extends Service implements Runnable, MediaPlayer.On
} else if (Intent.ACTION_MEDIA_SCANNER_FINISHED.equals(action)
|| Intent.ACTION_MEDIA_SCANNER_SCAN_FILE.equals(action)) {
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 RETRIEVE_SONGS = 9;
private static final int CALL = 10;
+ private static final int DO = 11;
public void run()
{
@@ -376,6 +404,16 @@ public class PlaybackService extends Service implements Runnable, MediaPlayer.On
}
}
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_MEDIA_SCANNER_FINISHED);
filter.addAction(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
+ filter.addAction(TOGGLE_PLAYBACK);
+ filter.addAction(NEXT_SONG);
+ filter.addAction(APPWIDGET_SMALL_UPDATE);
registerReceiver(mReceiver, filter);
PowerManager powerManager = (PowerManager)getSystemService(POWER_SERVICE);
@@ -554,6 +595,8 @@ public class PlaybackService extends Service implements Runnable, MediaPlayer.On
mSongTimeline.remove(0);
--mCurrentSong;
}
+
+ updateWidgets();
}
public void onCompletion(MediaPlayer player)
@@ -598,4 +641,15 @@ public class PlaybackService extends Service implements Runnable, MediaPlayer.On
return mSongTimeline.get(pos);
}
+
+ private void updateWidgets()
+ {
+ Song song = getSong(0);
+ OneCellWidget.update(this, song);
+ }
+
+ private void resetWidgets()
+ {
+ OneCellWidget.reset(this);
+ }
}
\ No newline at end of file