diff --git a/src/org/kreed/vanilla/PlaybackService.java b/src/org/kreed/vanilla/PlaybackService.java index 679db0e5..e3b7ecad 100644 --- a/src/org/kreed/vanilla/PlaybackService.java +++ b/src/org/kreed/vanilla/PlaybackService.java @@ -22,15 +22,18 @@ package org.kreed.vanilla; -import android.app.NotificationManager; -import android.app.Service; import android.app.backup.BackupManager; +import android.app.Notification; +import android.app.NotificationManager; +import android.app.PendingIntent; +import android.app.Service; import android.appwidget.AppWidgetManager; import android.content.BroadcastReceiver; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.content.res.TypedArray; import android.content.SharedPreferences; import android.database.ContentObserver; import android.database.Cursor; @@ -48,6 +51,7 @@ import android.provider.MediaStore; import android.telephony.PhoneStateListener; import android.telephony.TelephonyManager; import android.util.Log; +import android.widget.RemoteViews; import android.widget.Toast; import java.io.DataInputStream; import java.io.DataOutputStream; @@ -166,6 +170,19 @@ public final class PlaybackService extends Service implements Handler.Callback, public static final int WHEN_PLAYING = 1; public static final int ALWAYS = 2; + /** + * Notification click action: open LaunchActivity. + */ + private static final int NOT_ACTION_MAIN_ACTIVITY = 0; + /** + * Notification click action: open MiniPlaybackActivity. + */ + private static final int NOT_ACTION_MINI_ACTIVITY = 1; + /** + * Notification click action: skip to next song. + */ + private static final int NOT_ACTION_NEXT_SONG = 2; + private static final Object sWait = new Object(); private static PlaybackService sInstance; private static final ArrayList sActivities = new ArrayList(5); @@ -199,6 +216,15 @@ public final class PlaybackService extends Service implements Handler.Callback, * The time to wait before considering the player idle. */ private int mIdleTimeout; + /** + * The intent for the notification to execute, created by + * {@link PlaybackService#createNotificationAction(SharedPreferences)}. + */ + private PendingIntent mNotificationAction; + /** + * Use white text instead of black default text in notification. + */ + private boolean mInvertNotification; private Looper mLooper; private Handler mHandler; @@ -260,6 +286,8 @@ public final class PlaybackService extends Service implements Handler.Callback, mHeadsetOnly = settings.getBoolean("headset_only", false); mStockBroadcast = settings.getBoolean("stock_broadcast", false); mHeadsetPlay = settings.getBoolean("headset_play", false); + mInvertNotification = settings.getBoolean("notification_inverted_color", false); + mNotificationAction = createNotificationAction(settings); PowerManager powerManager = (PowerManager)getSystemService(POWER_SERVICE); mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "VanillaMusicLock"); @@ -371,8 +399,11 @@ public final class PlaybackService extends Service implements Handler.Callback, SharedPreferences settings = getSettings(this); if ("headset_pause".equals(key)) { mHeadsetPause = settings.getBoolean("headset_pause", true); - } else if ("remote_player".equals(key)) { - // the preference is loaded in SongNotification class + } else if ("notification_action".equals(key)) { + mNotificationAction = createNotificationAction(settings); + updateNotification(); + } else if ("notification_inverted_color".equals(key)) { + mInvertNotification = settings.getBoolean("notification_inverted_color", false); updateNotification(); } else if ("notification_mode".equals(key)){ mNotificationMode = Integer.parseInt(settings.getString("notification_mode", "1")); @@ -471,7 +502,7 @@ public final class PlaybackService extends Service implements Handler.Callback, mMediaPlayer.start(); if (mNotificationMode != NEVER) - startForeground(NOTIFICATION_ID, new SongNotification(this, mCurrentSong, true)); + startForeground(NOTIFICATION_ID, createNotification(mCurrentSong, mState)); if (mWakeLock != null) mWakeLock.acquire(); @@ -481,7 +512,7 @@ public final class PlaybackService extends Service implements Handler.Callback, if (mNotificationMode == ALWAYS) { stopForeground(false); - mNotificationManager.notify(NOTIFICATION_ID, new SongNotification(this, mCurrentSong, false)); + mNotificationManager.notify(NOTIFICATION_ID, createNotification(mCurrentSong, mState)); } else { stopForeground(true); } @@ -582,7 +613,7 @@ public final class PlaybackService extends Service implements Handler.Callback, private void updateNotification() { if ((mNotificationMode == ALWAYS || mNotificationMode == WHEN_PLAYING && (mState & FLAG_PLAYING) != 0) && mCurrentSong != null) - mNotificationManager.notify(NOTIFICATION_ID, new SongNotification(this, mCurrentSong, (mState & FLAG_PLAYING) != 0)); + mNotificationManager.notify(NOTIFICATION_ID, createNotification(mCurrentSong, mState)); else mNotificationManager.cancel(NOTIFICATION_ID); } @@ -1305,4 +1336,63 @@ public final class PlaybackService extends Service implements Handler.Callback, { return (state & MASK_SHUFFLE) >> 8; } + + /** + * Create a PendingIntent for use with the notification. + * + * @param prefs Where to load the action preference from. + */ + public PendingIntent createNotificationAction(SharedPreferences prefs) + { + switch (Integer.parseInt(prefs.getString("notification_action", "0"))) { + case NOT_ACTION_NEXT_SONG: { + Intent intent = new Intent(this, PlaybackService.class); + intent.setAction(PlaybackService.ACTION_NEXT_SONG_AUTOPLAY); + return PendingIntent.getService(this, 0, intent, 0); + } + case NOT_ACTION_MINI_ACTIVITY: { + Intent intent = new Intent(this, MiniPlaybackActivity.class); + return PendingIntent.getActivity(this, 0, intent, 0); + } + default: + Log.w("VanillaMusic", "Unknown value for notification_action. Defaulting to 0."); + // fall through + case NOT_ACTION_MAIN_ACTIVITY: { + Intent intent = new Intent(this, LaunchActivity.class); + return PendingIntent.getActivity(this, 0, intent, 0); + } + } + } + + /** + * Create a song notification. Call through the NotificationManager to + * display it. + * + * @param song The Song to display information about. + * @param state The state. Determines whether to show paused or playing icon. + */ + public Notification createNotification(Song song, int state) + { + int statusIcon = (state & FLAG_PLAYING) != 0 ? R.drawable.status_icon : R.drawable.status_icon_paused; + + RemoteViews views = new RemoteViews(getPackageName(), R.layout.notification); + views.setImageViewResource(R.id.icon, statusIcon); + views.setTextViewText(R.id.title, song.title); + views.setTextViewText(R.id.artist, song.artist); + + if (mInvertNotification) { + TypedArray array = getTheme().obtainStyledAttributes(new int[] { android.R.attr.textColorPrimary }); + int color = array.getColor(0, 0xFF00FF); + array.recycle(); + views.setTextColor(R.id.title, color); + views.setTextColor(R.id.artist, color); + } + + Notification notification = new Notification(); + notification.contentView = views; + notification.icon = statusIcon; + notification.flags |= Notification.FLAG_ONGOING_EVENT; + notification.contentIntent = mNotificationAction; + return notification; + } } diff --git a/src/org/kreed/vanilla/SongNotification.java b/src/org/kreed/vanilla/SongNotification.java deleted file mode 100644 index 3aa6ecf1..00000000 --- a/src/org/kreed/vanilla/SongNotification.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright (C) 2010 Christopher Eby - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package org.kreed.vanilla; - -import android.app.Notification; -import android.app.PendingIntent; -import android.content.Context; -import android.content.Intent; -import android.content.SharedPreferences; -import android.content.res.TypedArray; -import android.util.Log; -import android.widget.RemoteViews; - -/** - * Notification subclass that provides information about the current song. - * - * To the left of the view is the application icon. If playback is paused a - * the application with a paused icon overlayed is displayed instead. - * - * To the right are two lines of text. The upper line is the song title; the - * lower line is the song artist. - */ -public class SongNotification extends Notification { - /** - * Notification click action: open LaunchActivity. - */ - private static final int ACTION_MAIN_ACTIVITY = 0; - /** - * Notification click action: open MiniPlaybackActivity. - */ - private static final int ACTION_MINI_ACTIVITY = 1; - /** - * Notification click action: skip to next song. - */ - private static final int ACTION_NEXT_SONG = 2; - - /** - * Create a SongNotification. Call through the NotificationManager to - * display it. - * - * @param song The Song to display information about. - * @param playing True if music is playing. - */ - public SongNotification(Context context, Song song, boolean playing) - { - SharedPreferences prefs = PlaybackService.getSettings(context); - int action = Integer.parseInt(prefs.getString("notification_action", "0")); - int statusIcon = playing ? R.drawable.status_icon : R.drawable.status_icon_paused; - - RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.notification); - views.setImageViewResource(R.id.icon, statusIcon); - views.setTextViewText(R.id.title, song.title); - views.setTextViewText(R.id.artist, song.artist); - - if (prefs.getBoolean("notification_inverted_color", false)) { - TypedArray array = context.getTheme().obtainStyledAttributes(new int[] { android.R.attr.textColorPrimary }); - int color = array.getColor(0, 0xFF00FF); - array.recycle(); - views.setTextColor(R.id.title, color); - views.setTextColor(R.id.artist, color); - } - - contentView = views; - icon = statusIcon; - flags |= Notification.FLAG_ONGOING_EVENT; - - Intent intent; - switch (action) { - case ACTION_NEXT_SONG: - intent = new Intent(context, PlaybackService.class); - intent.setAction(PlaybackService.ACTION_NEXT_SONG_AUTOPLAY); - contentIntent = PendingIntent.getService(context, 0, intent, 0); - break; - case ACTION_MINI_ACTIVITY: - intent = new Intent(context, MiniPlaybackActivity.class); - contentIntent = PendingIntent.getActivity(context, 0, intent, 0); - break; - default: - Log.w("VanillaMusic", "Unknown value for notification_action. Defaulting to 0."); - // fall through - case ACTION_MAIN_ACTIVITY: - intent = new Intent(context, LaunchActivity.class); - contentIntent = PendingIntent.getActivity(context, 0, intent, 0); - break; - } - } -}