Controls in notification
This commit is contained in:
parent
48a4819392
commit
8d32bcf2ae
@ -1,14 +1,12 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
force=$1
|
|
||||||
|
|
||||||
gen() {
|
gen() {
|
||||||
name=`basename "$1" .svgz`
|
name=`basename "$1" .svgz`
|
||||||
png="res/drawable-$2/$name.png"
|
png="res/drawable-$2/$name.png"
|
||||||
if [[ "$1" -nt "$png" || $force ]]; then
|
if [ "$1" -nt "$png" -o ! -e "$png" ]; then
|
||||||
inkscape --without-gui --export-area-page --export-dpi=$3 --export-png="$png.out" $1
|
inkscape --without-gui --export-area-page --export-dpi=$3 --export-png="$png" $1
|
||||||
pngcrush -q -brute "$png.out" "$png"
|
convert -strip "$png" "$png"
|
||||||
rm "$png.out"
|
optipng -quiet -o7 "$png"
|
||||||
echo
|
echo
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
BIN
orig/notification_close.svgz
Normal file
BIN
orig/notification_close.svgz
Normal file
Binary file not shown.
BIN
res/drawable-hdpi/notification_close.png
Normal file
BIN
res/drawable-hdpi/notification_close.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 251 B |
BIN
res/drawable-mdpi/notification_close.png
Normal file
BIN
res/drawable-mdpi/notification_close.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 166 B |
BIN
res/drawable-xhdpi/notification_close.png
Normal file
BIN
res/drawable-xhdpi/notification_close.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 305 B |
88
res/layout-v11/notification.xml
Normal file
88
res/layout-v11/notification.xml
Normal 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>
|
@ -26,7 +26,7 @@ THE SOFTWARE.
|
|||||||
android:layout_gravity="center_vertical"
|
android:layout_gravity="center_vertical"
|
||||||
android:orientation="horizontal">
|
android:orientation="horizontal">
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/icon"
|
android:id="@+id/cover"
|
||||||
android:scaleType="fitCenter"
|
android:scaleType="fitCenter"
|
||||||
android:maxWidth="80dip"
|
android:maxWidth="80dip"
|
||||||
android:adjustViewBounds="true"
|
android:adjustViewBounds="true"
|
||||||
|
@ -28,12 +28,12 @@ import android.app.PendingIntent;
|
|||||||
import android.app.Service;
|
import android.app.Service;
|
||||||
import android.appwidget.AppWidgetManager;
|
import android.appwidget.AppWidgetManager;
|
||||||
import android.content.BroadcastReceiver;
|
import android.content.BroadcastReceiver;
|
||||||
|
import android.content.ComponentName;
|
||||||
import android.content.ContentResolver;
|
import android.content.ContentResolver;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.IntentFilter;
|
import android.content.IntentFilter;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.content.res.TypedArray;
|
|
||||||
import android.database.ContentObserver;
|
import android.database.ContentObserver;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
@ -113,6 +113,13 @@ public final class PlaybackService extends Service
|
|||||||
* instead.
|
* instead.
|
||||||
*/
|
*/
|
||||||
public static final String ACTION_TOGGLE_PLAYBACK_DELAYED = "org.kreed.vanilla.action.TOGGLE_PLAYBACK_DELAYED";
|
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.
|
* Action for startService: advance to the next song.
|
||||||
*/
|
*/
|
||||||
@ -144,16 +151,18 @@ public final class PlaybackService extends Service
|
|||||||
* when this is called.
|
* when this is called.
|
||||||
*/
|
*/
|
||||||
public static final String ACTION_PREVIOUS_SONG_AUTOPLAY = "org.kreed.vanilla.action.PREVIOUS_SONG_AUTOPLAY";
|
public static final String ACTION_PREVIOUS_SONG_AUTOPLAY = "org.kreed.vanilla.action.PREVIOUS_SONG_AUTOPLAY";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Change the shuffle mode.
|
* Change the shuffle mode.
|
||||||
*/
|
*/
|
||||||
public static final String ACTION_CYCLE_SHUFFLE = "org.kreed.vanilla.CYCLE_SHUFFLE";
|
public static final String ACTION_CYCLE_SHUFFLE = "org.kreed.vanilla.CYCLE_SHUFFLE";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Change the repeat mode.
|
* Change the repeat mode.
|
||||||
*/
|
*/
|
||||||
public static final String ACTION_CYCLE_REPEAT = "org.kreed.vanilla.CYCLE_REPEAT";
|
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 NEVER = 0;
|
||||||
public static final int WHEN_PLAYING = 1;
|
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.
|
* What to do when an accelerometer shake is detected.
|
||||||
*/
|
*/
|
||||||
private Action mShakeAction;
|
private Action mShakeAction;
|
||||||
|
/**
|
||||||
|
* If true, the notification should not be hidden when pausing regardless
|
||||||
|
* of user settings.
|
||||||
|
*/
|
||||||
|
private boolean mForceNotificationVisible;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate()
|
public void onCreate()
|
||||||
@ -453,6 +467,14 @@ public final class PlaybackService extends Service
|
|||||||
|
|
||||||
if (ACTION_TOGGLE_PLAYBACK.equals(action)) {
|
if (ACTION_TOGGLE_PLAYBACK.equals(action)) {
|
||||||
playPause();
|
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)) {
|
} else if (ACTION_TOGGLE_PLAYBACK_DELAYED.equals(action)) {
|
||||||
if (mHandler.hasMessages(CALL_GO, Integer.valueOf(0))) {
|
if (mHandler.hasMessages(CALL_GO, Integer.valueOf(0))) {
|
||||||
mHandler.removeMessages(CALL_GO, Integer.valueOf(0));
|
mHandler.removeMessages(CALL_GO, Integer.valueOf(0));
|
||||||
@ -493,6 +515,11 @@ public final class PlaybackService extends Service
|
|||||||
cycleFinishAction();
|
cycleFinishAction();
|
||||||
} else if (ACTION_CYCLE_SHUFFLE.equals(action)) {
|
} else if (ACTION_CYCLE_SHUFFLE.equals(action)) {
|
||||||
cycleShuffle();
|
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);
|
MediaButtonReceiver.registerMediaButton(this);
|
||||||
@ -708,7 +735,7 @@ public final class PlaybackService extends Service
|
|||||||
if (mMediaPlayerInitialized)
|
if (mMediaPlayerInitialized)
|
||||||
mMediaPlayer.pause();
|
mMediaPlayer.pause();
|
||||||
|
|
||||||
if (mNotificationMode == ALWAYS) {
|
if (mNotificationMode == ALWAYS || mForceNotificationVisible) {
|
||||||
stopForeground(false);
|
stopForeground(false);
|
||||||
mNotificationManager.notify(NOTIFICATION_ID, createNotification(mCurrentSong, mState));
|
mNotificationManager.notify(NOTIFICATION_ID, createNotification(mCurrentSong, mState));
|
||||||
} else {
|
} else {
|
||||||
@ -818,7 +845,7 @@ public final class PlaybackService extends Service
|
|||||||
|
|
||||||
private void updateNotification()
|
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));
|
mNotificationManager.notify(NOTIFICATION_ID, createNotification(mCurrentSong, mState));
|
||||||
else
|
else
|
||||||
mNotificationManager.cancel(NOTIFICATION_ID);
|
mNotificationManager.cancel(NOTIFICATION_ID);
|
||||||
@ -865,6 +892,7 @@ public final class PlaybackService extends Service
|
|||||||
*/
|
*/
|
||||||
public int playPause()
|
public int playPause()
|
||||||
{
|
{
|
||||||
|
mForceNotificationVisible = false;
|
||||||
synchronized (mStateLock) {
|
synchronized (mStateLock) {
|
||||||
if ((mState & FLAG_PLAYING) != 0)
|
if ((mState & FLAG_PLAYING) != 0)
|
||||||
return pause();
|
return pause();
|
||||||
@ -1621,23 +1649,40 @@ public final class PlaybackService extends Service
|
|||||||
|
|
||||||
Bitmap cover = song.getCover(this);
|
Bitmap cover = song.getCover(this);
|
||||||
if (cover == null) {
|
if (cover == null) {
|
||||||
views.setImageViewResource(R.id.icon, R.drawable.icon);
|
views.setImageViewResource(R.id.cover, R.drawable.albumart_mp_unknown_list);
|
||||||
} else {
|
} else {
|
||||||
views.setImageViewBitmap(R.id.icon, cover);
|
views.setImageViewBitmap(R.id.cover, cover);
|
||||||
}
|
}
|
||||||
if (playing) {
|
|
||||||
views.setTextViewText(R.id.title, song.title);
|
String title = song.title;
|
||||||
} else {
|
|
||||||
views.setTextViewText(R.id.title, getResources().getString(R.string.notification_title_paused, 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);
|
views.setTextViewText(R.id.artist, song.artist);
|
||||||
|
|
||||||
if (mInvertNotification) {
|
if (mInvertNotification) {
|
||||||
TypedArray array = getTheme().obtainStyledAttributes(new int[] { android.R.attr.textColorPrimary });
|
views.setTextColor(R.id.title, 0xffffffff);
|
||||||
int color = array.getColor(0, 0xFF00FF);
|
views.setTextColor(R.id.artist, 0xffffffff);
|
||||||
array.recycle();
|
|
||||||
views.setTextColor(R.id.title, color);
|
|
||||||
views.setTextColor(R.id.artist, color);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Notification notification = new Notification();
|
Notification notification = new Notification();
|
||||||
@ -1659,6 +1704,7 @@ public final class PlaybackService extends Service
|
|||||||
case AudioManager.AUDIOFOCUS_LOSS:
|
case AudioManager.AUDIOFOCUS_LOSS:
|
||||||
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
|
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
|
||||||
mDuckedLoss = false;
|
mDuckedLoss = false;
|
||||||
|
mForceNotificationVisible = true;
|
||||||
unsetFlag(FLAG_PLAYING);
|
unsetFlag(FLAG_PLAYING);
|
||||||
break;
|
break;
|
||||||
case AudioManager.AUDIOFOCUS_GAIN:
|
case AudioManager.AUDIOFOCUS_GAIN:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user