From e9b82d2c36cd4f546c30b5964d762972f920042a Mon Sep 17 00:00:00 2001 From: avm99963 Date: Tue, 15 Sep 2020 20:29:42 +0200 Subject: Add the option to display MediaStyle notifications Android now has the capability of displaying MediaStyle notifications which are better aligned with the Material Design standards and blend better into the OS than custom notifications. This commit adds an option in the Playback section to show notifications using the MediaStyle style. --- .../daneren2005/dsub/service/DownloadService.java | 10 +- .../github/daneren2005/dsub/util/Constants.java | 1 + .../daneren2005/dsub/util/Notifications.java | 178 ++++++++++++++------- .../res/drawable/ic_baseline_fast_forward_32.xml | 5 + .../res/drawable/ic_baseline_fast_rewind_32.xml | 5 + app/src/main/res/drawable/ic_baseline_pause_48.xml | 5 + app/src/main/res/drawable/ic_baseline_pause_64.xml | 5 + .../res/drawable/ic_baseline_play_arrow_48.xml | 5 + .../res/drawable/ic_baseline_play_arrow_64.xml | 5 + .../main/res/drawable/ic_baseline_skip_next_32.xml | 5 + .../res/drawable/ic_baseline_skip_previous_32.xml | 5 + app/src/main/res/values-es/strings.xml | 2 + app/src/main/res/values/strings.xml | 2 + app/src/main/res/xml/settings_playback.xml | 6 + 14 files changed, 180 insertions(+), 59 deletions(-) create mode 100644 app/src/main/res/drawable/ic_baseline_fast_forward_32.xml create mode 100644 app/src/main/res/drawable/ic_baseline_fast_rewind_32.xml create mode 100644 app/src/main/res/drawable/ic_baseline_pause_48.xml create mode 100644 app/src/main/res/drawable/ic_baseline_pause_64.xml create mode 100644 app/src/main/res/drawable/ic_baseline_play_arrow_48.xml create mode 100644 app/src/main/res/drawable/ic_baseline_play_arrow_64.xml create mode 100644 app/src/main/res/drawable/ic_baseline_skip_next_32.xml create mode 100644 app/src/main/res/drawable/ic_baseline_skip_previous_32.xml diff --git a/app/src/main/java/github/daneren2005/dsub/service/DownloadService.java b/app/src/main/java/github/daneren2005/dsub/service/DownloadService.java index e9096900..5c077b1e 100644 --- a/app/src/main/java/github/daneren2005/dsub/service/DownloadService.java +++ b/app/src/main/java/github/daneren2005/dsub/service/DownloadService.java @@ -1519,12 +1519,14 @@ public class DownloadService extends Service { Util.requestAudioFocus(this, audioManager); } + SharedPreferences prefs = Util.getPreferences(this); + boolean usingMediaStyleNotification = prefs.getBoolean(Constants.PREFERENCES_KEY_MEDIA_STYLE_NOTIFICATION, false) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP; + if (show) { - Notifications.showPlayingNotification(this, this, handler, currentPlaying.getSong()); + Notifications.showPlayingNotification(this, this, handler, currentPlaying.getSong(), usingMediaStyleNotification); } else if (pause) { - SharedPreferences prefs = Util.getPreferences(this); - if(prefs.getBoolean(Constants.PREFERENCES_KEY_PERSISTENT_NOTIFICATION, false)) { - Notifications.showPlayingNotification(this, this, handler, currentPlaying.getSong()); + if (prefs.getBoolean(Constants.PREFERENCES_KEY_PERSISTENT_NOTIFICATION, false) || usingMediaStyleNotification) { + Notifications.showPlayingNotification(this, this, handler, currentPlaying.getSong(), usingMediaStyleNotification); } else { Notifications.hidePlayingNotification(this, this, handler); } diff --git a/app/src/main/java/github/daneren2005/dsub/util/Constants.java b/app/src/main/java/github/daneren2005/dsub/util/Constants.java index 017ba2f3..933f531f 100644 --- a/app/src/main/java/github/daneren2005/dsub/util/Constants.java +++ b/app/src/main/java/github/daneren2005/dsub/util/Constants.java @@ -117,6 +117,7 @@ public final class Constants { public static final String PREFERENCES_EQUALIZER_ON = "equalizerOn"; public static final String PREFERENCES_EQUALIZER_SETTINGS = "equalizerSettings"; public static final String PREFERENCES_KEY_PERSISTENT_NOTIFICATION = "persistentNotification"; + public static final String PREFERENCES_KEY_MEDIA_STYLE_NOTIFICATION = "mediaStyleNotification"; public static final String PREFERENCES_KEY_GAPLESS_PLAYBACK = "gaplessPlayback"; public static final String PREFERENCES_KEY_REMOVE_PLAYED = "removePlayed"; public static final String PREFERENCES_KEY_KEEP_PLAYED_CNT = "keepPlayedCount"; diff --git a/app/src/main/java/github/daneren2005/dsub/util/Notifications.java b/app/src/main/java/github/daneren2005/dsub/util/Notifications.java index a8f7add0..35ab505d 100644 --- a/app/src/main/java/github/daneren2005/dsub/util/Notifications.java +++ b/app/src/main/java/github/daneren2005/dsub/util/Notifications.java @@ -43,6 +43,7 @@ import github.daneren2005.dsub.domain.PlayerState; import github.daneren2005.dsub.provider.DSubWidgetProvider; import github.daneren2005.dsub.service.DownloadFile; import github.daneren2005.dsub.service.DownloadService; +import github.daneren2005.dsub.util.compat.RemoteControlClientLP; import github.daneren2005.dsub.view.UpdateView; public final class Notifications { @@ -65,43 +66,89 @@ public final class Notifications { private final static Pair NOTIFICATION_TEXT_COLORS = new Pair(); - public static void showPlayingNotification(final Context context, final DownloadService downloadService, final Handler handler, MusicDirectory.Entry song) { + public static void showPlayingNotification(final Context context, final DownloadService downloadService, final Handler handler, MusicDirectory.Entry song, boolean usingMediaStyleNotification) { if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { getPlayingNotificationChannel(context); } - // Set the icon, scrolling text and timestamp - final Notification notification = new NotificationCompat.Builder(context) - .setSmallIcon(R.drawable.stat_notify_playing) - .setTicker(song.getTitle()) - .setWhen(System.currentTimeMillis()) - .setChannelId("now-playing-channel") - .build(); + final Notification notification; final boolean playing = downloadService.getPlayerState() == PlayerState.STARTED; - if(playing) { - notification.flags |= Notification.FLAG_NO_CLEAR | Notification.FLAG_ONGOING_EVENT; - } + boolean remote = downloadService.isRemoteEnabled(); boolean isSingle = downloadService.isCurrentPlayingSingle(); boolean shouldFastForward = downloadService.shouldFastForward(); - if (Build.VERSION.SDK_INT>= Build.VERSION_CODES.JELLY_BEAN){ - RemoteViews expandedContentView = new RemoteViews(context.getPackageName(), R.layout.notification_expanded); - setupViews(expandedContentView ,context, song, true, playing, remote, isSingle, shouldFastForward); - notification.bigContentView = expandedContentView; - notification.priority = Notification.PRIORITY_HIGH; - } - if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - notification.visibility = Notification.VISIBILITY_PUBLIC; - if(Util.getPreferences(context).getBoolean(Constants.PREFERENCES_KEY_HEADS_UP_NOTIFICATION, false) && !UpdateView.hasActiveActivity()) { - notification.vibrate = new long[0]; + if (usingMediaStyleNotification) { + RemoteControlClientLP remoteControlClient = (RemoteControlClientLP) downloadService.getRemoteControlClient(); + + android.support.v4.media.app.NotificationCompat.MediaStyle mediaStyle = new android.support.v4.media.app.NotificationCompat.MediaStyle() + .setMediaSession(remoteControlClient.getMediaSession().getSessionToken()); + + if (isSingle) { + mediaStyle.setShowActionsInCompactView(1); + } else { + mediaStyle.setShowActionsInCompactView(0, 2, 4); + } + + NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(context, "now-playing-channel") + .setSmallIcon(R.drawable.stat_notify_playing) + .setStyle(mediaStyle); + + PendingIntent prevIntent = null; + PendingIntent nextIntent = null; + if (!isSingle) { + prevIntent = getMediaPendingIntent("KEYCODE_MEDIA_PREVIOUS", context); + nextIntent = getMediaPendingIntent("KEYCODE_MEDIA_NEXT", context); + } + + PendingIntent rewindIntent = getMediaPendingIntent("KEYCODE_MEDIA_REWIND", context); + PendingIntent playIntent = getMediaPendingIntent(playing ? "KEYCODE_MEDIA_PLAY_PAUSE" : "KEYCODE_MEDIA_START", context); + PendingIntent forwardIntent = getMediaPendingIntent("KEYCODE_MEDIA_FAST_FORWARD", context); + + if (!isSingle) { + notificationBuilder.addAction(R.drawable.ic_baseline_skip_previous_32, "Previous", prevIntent); + } + + notificationBuilder.addAction(R.drawable.ic_baseline_fast_rewind_32, "Rewind", rewindIntent); + notificationBuilder.addAction(playing ? R.drawable.ic_baseline_pause_48 : R.drawable.ic_baseline_play_arrow_48, playing ? "Pause" : "Play", playIntent); + notificationBuilder.addAction(R.drawable.ic_baseline_fast_forward_32, "Forward", forwardIntent); + + if (!isSingle) { + notificationBuilder.addAction(R.drawable.ic_baseline_skip_next_32, "Next", nextIntent); + } + + notification = notificationBuilder.build(); + } else { + // Set the icon, scrolling text and timestamp + notification = new NotificationCompat.Builder(context, "now-playing-channel") + .setSmallIcon(R.drawable.stat_notify_playing) + .setTicker(song.getTitle()) + .setWhen(System.currentTimeMillis()) + .build(); + + if(playing) { + notification.flags |= Notification.FLAG_NO_CLEAR | Notification.FLAG_ONGOING_EVENT; + } + + if (Build.VERSION.SDK_INT>= Build.VERSION_CODES.JELLY_BEAN){ + RemoteViews expandedContentView = new RemoteViews(context.getPackageName(), R.layout.notification_expanded); + setupViews(expandedContentView, context, song, true, playing, remote, isSingle, shouldFastForward); + notification.bigContentView = expandedContentView; + notification.priority = Notification.PRIORITY_HIGH; + } + if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + notification.visibility = Notification.VISIBILITY_PUBLIC; + + if(Util.getPreferences(context).getBoolean(Constants.PREFERENCES_KEY_HEADS_UP_NOTIFICATION, false) && !UpdateView.hasActiveActivity()) { + notification.vibrate = new long[0]; + } } - } - RemoteViews smallContentView = new RemoteViews(context.getPackageName(), R.layout.notification); - setupViews(smallContentView, context, song, false, playing, remote, isSingle, shouldFastForward); - notification.contentView = smallContentView; + RemoteViews smallContentView = new RemoteViews(context.getPackageName(), R.layout.notification); + setupViews(smallContentView, context, song, false, playing, remote, isSingle, shouldFastForward); + notification.contentView = smallContentView; + } Intent notificationIntent = new Intent(context, SubsonicFragmentActivity.class); notificationIntent.putExtra(Constants.INTENT_EXTRA_NAME_DOWNLOAD, true); @@ -154,10 +201,52 @@ public final class Notifications { DSubWidgetProvider.notifyInstances(context, downloadService, playing); } + private static PendingIntent getMediaPendingIntent(String action, Context context) { + Intent intent = new Intent(action); + intent.setComponent(new ComponentName(context, DownloadService.class)); + + int keyCode = 0; + switch (action) { + case "KEYCODE_MEDIA_PREVIOUS": + keyCode = KeyEvent.KEYCODE_MEDIA_PREVIOUS; + break; + + case "KEYCODE_MEDIA_REWIND": + keyCode = KeyEvent.KEYCODE_MEDIA_REWIND; + break; + + case "KEYCODE_MEDIA_PLAY_PAUSE": + keyCode = KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE; + break; + + case "KEYCODE_MEDIA_START": + keyCode = KeyEvent.KEYCODE_MEDIA_PLAY; + break; + + case "KEYCODE_MEDIA_NEXT": + keyCode = KeyEvent.KEYCODE_MEDIA_NEXT; + break; + + case "KEYCODE_MEDIA_FAST_FORWARD": + keyCode = KeyEvent.KEYCODE_MEDIA_FAST_FORWARD; + break; + + case "KEYCODE_MEDIA_STOP": + keyCode = KeyEvent.KEYCODE_MEDIA_STOP; + break; + } + + if (keyCode != 0) { + intent.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_UP, keyCode)); + } + + return PendingIntent.getService(context, 0, intent, 0); + } + private static void setupViews(RemoteViews rv, Context context, MusicDirectory.Entry song, boolean expanded, boolean playing, boolean remote, boolean isSingleFile, boolean shouldFastForward) { // Use the same text for the ticker and the expanded notification String title = song.getTitle(); - String arist = song.getArtist(); + String artist = song.getArtist(); String album = song.getAlbum(); // Set the album art. @@ -181,7 +270,7 @@ public final class Notifications { // set the text for the notifications rv.setTextViewText(R.id.notification_title, title); - rv.setTextViewText(R.id.notification_artist, arist); + rv.setTextViewText(R.id.notification_artist, artist); rv.setTextViewText(R.id.notification_album, album); boolean persistent = Util.getPreferences(context).getBoolean(Constants.PREFERENCES_KEY_PERSISTENT_NOTIFICATION, false); @@ -276,53 +365,32 @@ public final class Notifications { PendingIntent pendingIntent; if(previous > 0) { - Intent prevIntent = new Intent("KEYCODE_MEDIA_PREVIOUS"); - prevIntent.setComponent(new ComponentName(context, DownloadService.class)); - prevIntent.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_MEDIA_PREVIOUS)); - pendingIntent = PendingIntent.getService(context, 0, prevIntent, 0); + pendingIntent = getMediaPendingIntent("KEYCODE_MEDIA_PREVIOUS", context); rv.setOnClickPendingIntent(previous, pendingIntent); } if(rewind > 0) { - Intent rewindIntent = new Intent("KEYCODE_MEDIA_REWIND"); - rewindIntent.setComponent(new ComponentName(context, DownloadService.class)); - rewindIntent.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_MEDIA_REWIND)); - pendingIntent = PendingIntent.getService(context, 0, rewindIntent, 0); + pendingIntent = getMediaPendingIntent("KEYCODE_MEDIA_REWIND", context); rv.setOnClickPendingIntent(rewind, pendingIntent); } if(pause > 0) { if(playing) { - Intent pauseIntent = new Intent("KEYCODE_MEDIA_PLAY_PAUSE"); - pauseIntent.setComponent(new ComponentName(context, DownloadService.class)); - pauseIntent.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE)); - pendingIntent = PendingIntent.getService(context, 0, pauseIntent, 0); + pendingIntent = getMediaPendingIntent("KEYCODE_MEDIA_PLAY_PAUSE", context); rv.setOnClickPendingIntent(pause, pendingIntent); } else { - Intent prevIntent = new Intent("KEYCODE_MEDIA_START"); - prevIntent.setComponent(new ComponentName(context, DownloadService.class)); - prevIntent.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_MEDIA_PLAY)); - pendingIntent = PendingIntent.getService(context, 0, prevIntent, 0); + pendingIntent = getMediaPendingIntent("KEYCODE_MEDIA_START", context); rv.setOnClickPendingIntent(pause, pendingIntent); } } if(next > 0) { - Intent nextIntent = new Intent("KEYCODE_MEDIA_NEXT"); - nextIntent.setComponent(new ComponentName(context, DownloadService.class)); - nextIntent.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_MEDIA_NEXT)); - pendingIntent = PendingIntent.getService(context, 0, nextIntent, 0); + pendingIntent = getMediaPendingIntent("KEYCODE_MEDIA_NEXT", context); rv.setOnClickPendingIntent(next, pendingIntent); } if(fastForward > 0) { - Intent fastForwardIntent = new Intent("KEYCODE_MEDIA_FAST_FORWARD"); - fastForwardIntent.setComponent(new ComponentName(context, DownloadService.class)); - fastForwardIntent.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_MEDIA_FAST_FORWARD)); - pendingIntent = PendingIntent.getService(context, 0, fastForwardIntent, 0); + pendingIntent = getMediaPendingIntent("KEYCODE_MEDIA_FAST_FORWARD", context); rv.setOnClickPendingIntent(fastForward, pendingIntent); } if(close > 0) { - Intent prevIntent = new Intent("KEYCODE_MEDIA_STOP"); - prevIntent.setComponent(new ComponentName(context, DownloadService.class)); - prevIntent.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_MEDIA_STOP)); - pendingIntent = PendingIntent.getService(context, 0, prevIntent, 0); + pendingIntent = getMediaPendingIntent("KEYCODE_MEDIA_STOP", context); rv.setOnClickPendingIntent(close, pendingIntent); } } diff --git a/app/src/main/res/drawable/ic_baseline_fast_forward_32.xml b/app/src/main/res/drawable/ic_baseline_fast_forward_32.xml new file mode 100644 index 00000000..2ed77118 --- /dev/null +++ b/app/src/main/res/drawable/ic_baseline_fast_forward_32.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/drawable/ic_baseline_fast_rewind_32.xml b/app/src/main/res/drawable/ic_baseline_fast_rewind_32.xml new file mode 100644 index 00000000..d2546368 --- /dev/null +++ b/app/src/main/res/drawable/ic_baseline_fast_rewind_32.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/drawable/ic_baseline_pause_48.xml b/app/src/main/res/drawable/ic_baseline_pause_48.xml new file mode 100644 index 00000000..8d5e417e --- /dev/null +++ b/app/src/main/res/drawable/ic_baseline_pause_48.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/drawable/ic_baseline_pause_64.xml b/app/src/main/res/drawable/ic_baseline_pause_64.xml new file mode 100644 index 00000000..8de9e59e --- /dev/null +++ b/app/src/main/res/drawable/ic_baseline_pause_64.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/drawable/ic_baseline_play_arrow_48.xml b/app/src/main/res/drawable/ic_baseline_play_arrow_48.xml new file mode 100644 index 00000000..c775d2c0 --- /dev/null +++ b/app/src/main/res/drawable/ic_baseline_play_arrow_48.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/drawable/ic_baseline_play_arrow_64.xml b/app/src/main/res/drawable/ic_baseline_play_arrow_64.xml new file mode 100644 index 00000000..f42648b8 --- /dev/null +++ b/app/src/main/res/drawable/ic_baseline_play_arrow_64.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/drawable/ic_baseline_skip_next_32.xml b/app/src/main/res/drawable/ic_baseline_skip_next_32.xml new file mode 100644 index 00000000..23a02ee0 --- /dev/null +++ b/app/src/main/res/drawable/ic_baseline_skip_next_32.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/drawable/ic_baseline_skip_previous_32.xml b/app/src/main/res/drawable/ic_baseline_skip_previous_32.xml new file mode 100644 index 00000000..e01d6666 --- /dev/null +++ b/app/src/main/res/drawable/ic_baseline_skip_previous_32.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index a5273a50..9076cf78 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -403,6 +403,8 @@ Tags de pistas Abrir en pestaña Abrir directamente a esta pestaña + Notificaciones nativas multimedia de Android (5.0+) + Mostrar las notificaciones de reproducción como notificaciones de estilo multimedia nativas (solo en Android Lollipop y superior) Expira: %s Nunca expira diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index be1a7bff..17e96487 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -495,6 +495,8 @@ If you are having battery drain problems on Android 7.0 try turning this off Rewind Interval Fast Forward Interval + Native Android media notification (5.0+) + Show playing notifications as native media style notifications (Android Lollipop+ only) Shuffle By Start Year: diff --git a/app/src/main/res/xml/settings_playback.xml b/app/src/main/res/xml/settings_playback.xml index fb3501f0..f2e76b4c 100644 --- a/app/src/main/res/xml/settings_playback.xml +++ b/app/src/main/res/xml/settings_playback.xml @@ -46,6 +46,12 @@ android:key="headsUpNotification" android:defaultValue="false"/> + +