Controls in notification
This commit is contained in:
parent
48a4819392
commit
8d32bcf2ae
@ -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
|
||||
}
|
||||
|
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: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>
|
||||
|
@ -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:
|
||||
|
Loading…
x
Reference in New Issue
Block a user