Controls in notification

This commit is contained in:
Christopher Eby 2012-02-18 01:46:38 -06:00
parent 48a4819392
commit 8d32bcf2ae
8 changed files with 156 additions and 24 deletions

View File

@ -1,14 +1,12 @@
#!/bin/sh
force=$1
gen() {
name=`basename "$1" .svgz`
png="res/drawable-$2/$name.png"
if [[ "$1" -nt "$png" || $force ]]; then
inkscape --without-gui --export-area-page --export-dpi=$3 --export-png="$png.out" $1
pngcrush -q -brute "$png.out" "$png"
rm "$png.out"
if [ "$1" -nt "$png" -o ! -e "$png" ]; then
inkscape --without-gui --export-area-page --export-dpi=$3 --export-png="$png" $1
convert -strip "$png" "$png"
optipng -quiet -o7 "$png"
echo
fi
}

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 251 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 166 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 305 B

View File

@ -0,0 +1,88 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2012 Christopher Eby <kreed@kreed.org>
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.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_gravity="center_vertical"
android:orientation="horizontal">
<ImageView
android:id="@+id/cover"
android:scaleType="fitCenter"
android:maxWidth="80dip"
android:adjustViewBounds="true"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:layout_marginRight="5dip" />
<LinearLayout
android:layout_width="0px"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_gravity="center"
android:orientation="vertical">
<TextView
android:id="@+id/title"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textAppearance="@android:style/TextAppearance.StatusBar.EventContent.Title"
android:singleLine="true"
android:ellipsize="marquee" />
<TextView
android:id="@+id/artist"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textAppearance="@android:style/TextAppearance.StatusBar.EventContent"
android:singleLine="true"
android:ellipsize="marquee" />
</LinearLayout>
<ImageButton
android:id="@+id/play_pause"
android:paddingTop="5dip"
android:paddingBottom="5dip"
android:layout_height="42dip"
android:layout_width="wrap_content"
android:layout_gravity="center"
android:background="?android:attr/selectableItemBackground"
android:scaleType="fitCenter"
android:src="@drawable/play_normal"
android:contentDescription="@string/play_pause" />
<ImageButton
android:id="@+id/next"
android:paddingTop="5dip"
android:paddingBottom="5dip"
android:layout_height="42dip"
android:layout_width="wrap_content"
android:layout_gravity="center"
android:background="?android:attr/selectableItemBackground"
android:scaleType="fitCenter"
android:src="@drawable/next_normal"
android:contentDescription="@string/next_song" />
<ImageButton
android:id="@+id/close"
android:padding="5dip"
android:layout_height="42dip"
android:layout_width="wrap_content"
android:layout_gravity="center"
android:background="?android:attr/selectableItemBackground"
android:scaleType="fitCenter"
android:src="@drawable/notification_close" />
</LinearLayout>

View File

@ -26,7 +26,7 @@ THE SOFTWARE.
android:layout_gravity="center_vertical"
android:orientation="horizontal">
<ImageView
android:id="@+id/icon"
android:id="@+id/cover"
android:scaleType="fitCenter"
android:maxWidth="80dip"
android:adjustViewBounds="true"
@ -53,4 +53,4 @@ THE SOFTWARE.
android:singleLine="true"
android:ellipsize="marquee" />
</LinearLayout>
</LinearLayout>
</LinearLayout>

View File

@ -28,12 +28,12 @@ import android.app.PendingIntent;
import android.app.Service;
import android.appwidget.AppWidgetManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.content.res.TypedArray;
import android.database.ContentObserver;
import android.database.Cursor;
import android.graphics.Bitmap;
@ -113,6 +113,13 @@ public final class PlaybackService extends Service
* instead.
*/
public static final String ACTION_TOGGLE_PLAYBACK_DELAYED = "org.kreed.vanilla.action.TOGGLE_PLAYBACK_DELAYED";
/**
* Action for startService: toggle playback on/off.
*
* This works the same way as ACTION_PLAY_PAUSE but prevents the notification
* from being hidden regardless of notification visibility settings.
*/
public static final String ACTION_TOGGLE_PLAYBACK_NOTIFICATION = "org.kreed.vanilla.action.TOGGLE_PLAYBACK_NOTIFICATION";
/**
* Action for startService: advance to the next song.
*/
@ -144,16 +151,18 @@ public final class PlaybackService extends Service
* when this is called.
*/
public static final String ACTION_PREVIOUS_SONG_AUTOPLAY = "org.kreed.vanilla.action.PREVIOUS_SONG_AUTOPLAY";
/**
* Change the shuffle mode.
*/
public static final String ACTION_CYCLE_SHUFFLE = "org.kreed.vanilla.CYCLE_SHUFFLE";
/**
* Change the repeat mode.
*/
public static final String ACTION_CYCLE_REPEAT = "org.kreed.vanilla.CYCLE_REPEAT";
/**
* Pause music and hide the notifcation.
*/
public static final String ACTION_CLOSE_NOTIFICATION = "org.kreed.vanilla.CLOSE_NOTIFICATION";
public static final int NEVER = 0;
public static final int WHEN_PLAYING = 1;
@ -353,6 +362,11 @@ public final class PlaybackService extends Service
* What to do when an accelerometer shake is detected.
*/
private Action mShakeAction;
/**
* If true, the notification should not be hidden when pausing regardless
* of user settings.
*/
private boolean mForceNotificationVisible;
@Override
public void onCreate()
@ -453,6 +467,14 @@ public final class PlaybackService extends Service
if (ACTION_TOGGLE_PLAYBACK.equals(action)) {
playPause();
} else if (ACTION_TOGGLE_PLAYBACK_NOTIFICATION.equals(action)) {
mForceNotificationVisible = true;
synchronized (mStateLock) {
if ((mState & FLAG_PLAYING) != 0)
pause();
else
play();
}
} else if (ACTION_TOGGLE_PLAYBACK_DELAYED.equals(action)) {
if (mHandler.hasMessages(CALL_GO, Integer.valueOf(0))) {
mHandler.removeMessages(CALL_GO, Integer.valueOf(0));
@ -493,6 +515,11 @@ public final class PlaybackService extends Service
cycleFinishAction();
} else if (ACTION_CYCLE_SHUFFLE.equals(action)) {
cycleShuffle();
} else if (ACTION_CLOSE_NOTIFICATION.equals(action)) {
mForceNotificationVisible = false;
pause();
stopForeground(true); // sometimes required to clear notification
mNotificationManager.cancel(NOTIFICATION_ID);
}
MediaButtonReceiver.registerMediaButton(this);
@ -708,7 +735,7 @@ public final class PlaybackService extends Service
if (mMediaPlayerInitialized)
mMediaPlayer.pause();
if (mNotificationMode == ALWAYS) {
if (mNotificationMode == ALWAYS || mForceNotificationVisible) {
stopForeground(false);
mNotificationManager.notify(NOTIFICATION_ID, createNotification(mCurrentSong, mState));
} else {
@ -818,7 +845,7 @@ public final class PlaybackService extends Service
private void updateNotification()
{
if ((mNotificationMode == ALWAYS || mNotificationMode == WHEN_PLAYING && (mState & FLAG_PLAYING) != 0) && mCurrentSong != null)
if ((mForceNotificationVisible || mNotificationMode == ALWAYS || mNotificationMode == WHEN_PLAYING && (mState & FLAG_PLAYING) != 0) && mCurrentSong != null)
mNotificationManager.notify(NOTIFICATION_ID, createNotification(mCurrentSong, mState));
else
mNotificationManager.cancel(NOTIFICATION_ID);
@ -865,6 +892,7 @@ public final class PlaybackService extends Service
*/
public int playPause()
{
mForceNotificationVisible = false;
synchronized (mStateLock) {
if ((mState & FLAG_PLAYING) != 0)
return pause();
@ -1621,23 +1649,40 @@ public final class PlaybackService extends Service
Bitmap cover = song.getCover(this);
if (cover == null) {
views.setImageViewResource(R.id.icon, R.drawable.icon);
views.setImageViewResource(R.id.cover, R.drawable.albumart_mp_unknown_list);
} else {
views.setImageViewBitmap(R.id.icon, cover);
views.setImageViewBitmap(R.id.cover, cover);
}
if (playing) {
views.setTextViewText(R.id.title, song.title);
} else {
views.setTextViewText(R.id.title, getResources().getString(R.string.notification_title_paused, song.title));
String title = song.title;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
int playButton = playing ? R.drawable.pause_normal : R.drawable.play_normal;
views.setImageViewResource(R.id.play_pause, playButton);
ComponentName service = new ComponentName(this, PlaybackService.class);
Intent playPause = new Intent(PlaybackService.ACTION_TOGGLE_PLAYBACK_NOTIFICATION);
playPause.setComponent(service);
views.setOnClickPendingIntent(R.id.play_pause, PendingIntent.getService(this, 0, playPause, 0));
Intent next = new Intent(PlaybackService.ACTION_NEXT_SONG);
next.setComponent(service);
views.setOnClickPendingIntent(R.id.next, PendingIntent.getService(this, 0, next, 0));
Intent close = new Intent(PlaybackService.ACTION_CLOSE_NOTIFICATION);
close.setComponent(service);
views.setOnClickPendingIntent(R.id.close, PendingIntent.getService(this, 0, close, 0));
} else if (!playing) {
title = getResources().getString(R.string.notification_title_paused, song.title);
}
views.setTextViewText(R.id.title, 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);
views.setTextColor(R.id.title, 0xffffffff);
views.setTextColor(R.id.artist, 0xffffffff);
}
Notification notification = new Notification();
@ -1659,6 +1704,7 @@ public final class PlaybackService extends Service
case AudioManager.AUDIOFOCUS_LOSS:
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
mDuckedLoss = false;
mForceNotificationVisible = true;
unsetFlag(FLAG_PLAYING);
break;
case AudioManager.AUDIOFOCUS_GAIN: