diff options
author | H. Lehmann <ByteHamster@users.noreply.github.com> | 2019-10-06 19:42:14 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-10-06 19:42:14 +0200 |
commit | 0e614f96e994fd4f3ed2e2bf3e628041da34648c (patch) | |
tree | 6ffceb6ebda8ee1c5a0cc0e461a135d52f9cbbb2 /core/src | |
parent | f750e06a1be5c93f7a8cffd49f56a57080583a82 (diff) | |
parent | 6f809b47e6a3d2929eaf31830bc0aa2b8abd87bb (diff) | |
download | AntennaPod-0e614f96e994fd4f3ed2e2bf3e628041da34648c.zip |
Merge pull request #3497 from ByteHamster/position-in-notification
Showing progress in notification
Diffstat (limited to 'core/src')
2 files changed, 131 insertions, 116 deletions
diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java index 848eacbd6..5c053763b 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java +++ b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java @@ -216,6 +216,7 @@ public class PlaybackService extends MediaBrowserServiceCompat { private PlaybackServiceFlavorHelper flavorHelper; private PlaybackServiceStateManager stateManager; private Disposable positionEventTimer; + private PlaybackServiceNotificationBuilder notificationBuilder; /** * Used for Lollipop notifications, Android Wear, and Android Auto. @@ -271,7 +272,7 @@ public class PlaybackService extends MediaBrowserServiceCompat { isRunning = true; stateManager = new PlaybackServiceStateManager(this); - PlaybackServiceNotificationBuilder notificationBuilder = new PlaybackServiceNotificationBuilder(this); + notificationBuilder = new PlaybackServiceNotificationBuilder(this); stateManager.startForeground(NOTIFICATION_ID, notificationBuilder.build()); registerReceiver(autoStateUpdated, new IntentFilter("com.google.android.gms.car.media.STATUS")); @@ -444,20 +445,9 @@ public class PlaybackService extends MediaBrowserServiceCompat { @Override public int onStartCommand(Intent intent, int flags, int startId) { super.onStartCommand(intent, flags, startId); - Log.d(TAG, "OnStartCommand called"); - if (!stateManager.isInForeground()) { - PlaybackServiceNotificationBuilder notificationBuilder = new PlaybackServiceNotificationBuilder(this); - if (mediaPlayer != null && getPlayable() != null) { - notificationBuilder.addMetadata(getPlayable(), mediaSession.getSessionToken(), getStatus(), isCasting); - if (notificationBuilder.isIconCached(getPlayable())) { - notificationBuilder.loadIcon(getPlayable()); - } - } - stateManager.startForeground(NOTIFICATION_ID, notificationBuilder.build()); - } - + stateManager.startForeground(NOTIFICATION_ID, notificationBuilder.build()); NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this); notificationManager.cancel(NOTIFICATION_ID_STREAMING); @@ -1195,59 +1185,51 @@ public class PlaybackService extends MediaBrowserServiceCompat { } private synchronized void setupNotification(final Playable playable) { + Log.d(TAG, "setupNotification"); if (notificationSetupThread != null) { notificationSetupThread.interrupt(); } - if (playable == null) { - Log.d(TAG, "setupNotification: playable is null" + Log.getStackTraceString(new Exception())); + if (playable == null || mediaPlayer == null) { + Log.d(TAG, "setupNotification: playable=" + playable); + Log.d(TAG, "setupNotification: mediaPlayer=" + mediaPlayer); if (!stateManager.hasReceivedValidStartCommand()) { stateManager.stopService(); } return; } - Runnable notificationSetupTask = new Runnable() { - @Override - public void run() { - Log.d(TAG, "Starting background work"); - if (mediaPlayer == null) { - Log.d(TAG, "notificationSetupTask: mediaPlayer is null"); - if (!stateManager.hasReceivedValidStartCommand()) { - stateManager.stopService(); - } - return; - } - PlayerStatus playerStatus = mediaPlayer.getPlayerStatus(); - PlaybackServiceNotificationBuilder notificationBuilder = - new PlaybackServiceNotificationBuilder(PlaybackService.this); - notificationBuilder.addMetadata(playable, mediaSession.getSessionToken(), playerStatus, isCasting); - - if (!notificationBuilder.isIconCached(playable)) { - // To make sure that the notification is shown instantly - notificationBuilder.loadDefaultIcon(); - stateManager.startForeground(NOTIFICATION_ID, notificationBuilder.build()); - } - notificationBuilder.loadIcon(playable); - - if (!Thread.currentThread().isInterrupted() && stateManager.hasReceivedValidStartCommand()) { - Notification notification = notificationBuilder.build(); - - if (playerStatus == PlayerStatus.PLAYING || - playerStatus == PlayerStatus.PREPARING || - playerStatus == PlayerStatus.SEEKING || - isCasting) { - stateManager.startForeground(NOTIFICATION_ID, notification); - } else { - stateManager.stopForeground(false); - NotificationManager mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); - mNotificationManager.notify(NOTIFICATION_ID, notification); - } - Log.d(TAG, "Notification set up"); + PlayerStatus playerStatus = mediaPlayer.getPlayerStatus(); + notificationBuilder.setMetadata(playable, mediaSession.getSessionToken(), playerStatus, isCasting); + notificationBuilder.updatePosition(getCurrentPosition(), getCurrentPlaybackSpeed()); + + Log.d(TAG, "setupNotification: startForeground" + playerStatus); + NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this); + notificationManager.notify(NOTIFICATION_ID, notificationBuilder.build()); + startForegroundIfPlaying(playerStatus); + + if (!notificationBuilder.isIconCached()) { + notificationSetupThread = new Thread(() -> { + Log.d(TAG, "Loading notification icon"); + notificationBuilder.loadIcon(); + if (!Thread.currentThread().isInterrupted()) { + notificationManager.notify(NOTIFICATION_ID, notificationBuilder.build()); } + }); + notificationSetupThread.start(); + } + } + + private void startForegroundIfPlaying(@NonNull PlayerStatus status) { + if (stateManager.hasReceivedValidStartCommand()) { + if (isCasting || status == PlayerStatus.PLAYING || status == PlayerStatus.PREPARING + || status == PlayerStatus.SEEKING) { + stateManager.startForeground(NOTIFICATION_ID, notificationBuilder.build()); + } else { + stateManager.stopForeground(false); + NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this); + notificationManager.notify(NOTIFICATION_ID, notificationBuilder.build()); } - }; - notificationSetupThread = new Thread(notificationSetupTask); - notificationSetupThread.start(); + } } /** @@ -1593,8 +1575,15 @@ public class PlaybackService extends MediaBrowserServiceCompat { Log.d(TAG, "Setting up position observer"); positionEventTimer = Observable.interval(1, TimeUnit.SECONDS) .observeOn(AndroidSchedulers.mainThread()) - .subscribe(aLong -> - EventBus.getDefault().post(new PlaybackPositionEvent(getCurrentPosition(), getDuration()))); + .subscribe(number -> { + EventBus.getDefault().post(new PlaybackPositionEvent(getCurrentPosition(), getDuration())); + if (Build.VERSION.SDK_INT < 29) { + notificationBuilder.updatePosition(getCurrentPosition(), getCurrentPlaybackSpeed()); + NotificationManager notificationManager = (NotificationManager) + getSystemService(NOTIFICATION_SERVICE); + notificationManager.notify(NOTIFICATION_ID, notificationBuilder.build()); + } + }); } private void cancelPositionObserver() { diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceNotificationBuilder.java b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceNotificationBuilder.java index b809ad659..b277a6bc2 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceNotificationBuilder.java +++ b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceNotificationBuilder.java @@ -1,6 +1,7 @@ package de.danoeh.antennapod.core.service.playback; import android.annotation.TargetApi; +import android.app.Notification; import android.app.PendingIntent; import android.content.Context; import android.content.Intent; @@ -10,78 +11,67 @@ import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.graphics.drawable.VectorDrawable; import android.os.Build; -import androidx.annotation.NonNull; -import androidx.core.app.NotificationCompat; -import androidx.core.content.ContextCompat; import android.support.v4.media.session.MediaSessionCompat; import android.util.Log; import android.view.KeyEvent; +import androidx.annotation.NonNull; +import androidx.core.app.NotificationCompat; +import androidx.core.content.ContextCompat; import com.bumptech.glide.Glide; import com.bumptech.glide.request.RequestOptions; -import de.danoeh.antennapod.core.ClientConfig; import de.danoeh.antennapod.core.R; import de.danoeh.antennapod.core.glide.ApGlideSettings; import de.danoeh.antennapod.core.preferences.UserPreferences; import de.danoeh.antennapod.core.receiver.MediaButtonReceiver; +import de.danoeh.antennapod.core.util.Converter; import de.danoeh.antennapod.core.util.IntList; +import de.danoeh.antennapod.core.util.TimeSpeedConverter; import de.danoeh.antennapod.core.util.gui.NotificationUtils; import de.danoeh.antennapod.core.util.playback.Playable; -public class PlaybackServiceNotificationBuilder extends NotificationCompat.Builder { +public class PlaybackServiceNotificationBuilder { private static final String TAG = "PlaybackSrvNotification"; private static Bitmap defaultIcon = null; private Context context; + private Playable playable; + private MediaSessionCompat.Token mediaSessionToken; + private PlayerStatus playerStatus; + private boolean isCasting; + private Bitmap icon; + private String position; public PlaybackServiceNotificationBuilder(@NonNull Context context) { - super(context, NotificationUtils.CHANNEL_ID_PLAYING); this.context = context; + } - final int smallIcon = ClientConfig.playbackServiceCallbacks.getNotificationIconResource(context); + public void setMetadata(Playable playable, MediaSessionCompat.Token mediaSessionToken, + PlayerStatus playerStatus, boolean isCasting) { - final PendingIntent pIntent = PendingIntent.getActivity(context, 0, - PlaybackService.getPlayerActivityIntent(context), - PendingIntent.FLAG_UPDATE_CURRENT); + if (playable != this.playable) { + clearCache(); + } + this.playable = playable; + this.mediaSessionToken = mediaSessionToken; + this.playerStatus = playerStatus; + this.isCasting = isCasting; + } - setContentTitle(context.getString(R.string.app_name)); - setContentText("Service is running"); // Just in case the notification is not updated (should not occur) - setOngoing(false); - setContentIntent(pIntent); - setWhen(0); // we don't need the time - setSmallIcon(smallIcon); - setPriority(NotificationCompat.PRIORITY_MIN); + private void clearCache() { + this.icon = null; + this.position = null; } - public void addMetadata(Playable playable, MediaSessionCompat.Token mediaSessionToken, PlayerStatus playerStatus, boolean isCasting) { - Log.v(TAG, "notificationSetupTask: playerStatus=" + playerStatus); - setContentTitle(playable.getFeedTitle()); - setContentText(playable.getEpisodeTitle()); - setPriority(UserPreferences.getNotifyPriority()); - addActions(mediaSessionToken, playerStatus, isCasting); - setVisibility(NotificationCompat.VISIBILITY_PUBLIC); - setColor(NotificationCompat.COLOR_DEFAULT); + public void updatePosition(int position,float speed) { + TimeSpeedConverter converter = new TimeSpeedConverter(speed); + this.position = Converter.getDurationStringLong(converter.convert(position)); } - public boolean isIconCached(Playable playable) { - int iconSize = context.getResources().getDimensionPixelSize(android.R.dimen.notification_large_icon_width); - try { - Bitmap icon = Glide.with(context) - .asBitmap() - .load(playable.getImageLocation()) - .apply(RequestOptions.diskCacheStrategyOf(ApGlideSettings.AP_DISK_CACHE_STRATEGY)) - .apply(new RequestOptions() - .centerCrop() - .onlyRetrieveFromCache(true)) - .submit(iconSize, iconSize) - .get(); - return icon != null; - } catch (Throwable tr) { - return false; - } + public boolean isIconCached() { + return icon != null; } - public void loadIcon(Playable playable) { - Bitmap icon = null; + public void loadIcon() { int iconSize = context.getResources().getDimensionPixelSize(android.R.dimen.notification_large_icon_width); try { icon = Glide.with(context) @@ -94,19 +84,13 @@ public class PlaybackServiceNotificationBuilder extends NotificationCompat.Build } catch (Throwable tr) { Log.e(TAG, "Error loading the media icon for the notification", tr); } - - if (icon == null) { - loadDefaultIcon(); - } else { - setLargeIcon(icon); - } } - public void loadDefaultIcon() { + private Bitmap getDefaultIcon() { if (defaultIcon == null) { defaultIcon = getBitmap(context, R.drawable.notification_default_large_icon); } - setLargeIcon(defaultIcon); + return defaultIcon; } @TargetApi(Build.VERSION_CODES.LOLLIPOP) @@ -130,7 +114,47 @@ public class PlaybackServiceNotificationBuilder extends NotificationCompat.Build } } - private void addActions(MediaSessionCompat.Token mediaSessionToken, PlayerStatus playerStatus, boolean isCasting) { + public Notification build() { + NotificationCompat.Builder notification = new NotificationCompat.Builder(context, + NotificationUtils.CHANNEL_ID_PLAYING); + + if (playable != null) { + notification.setContentTitle(playable.getFeedTitle()); + notification.setContentText(playable.getEpisodeTitle()); + addActions(notification, mediaSessionToken, playerStatus, isCasting); + + if (icon != null) { + notification.setLargeIcon(icon); + } else { + notification.setLargeIcon(getDefaultIcon()); + } + + if (Build.VERSION.SDK_INT < 29) { + notification.setSubText(position); + } + } else { + notification.setContentTitle(context.getString(R.string.app_name)); + notification.setContentText("Service is running"); + } + + notification.setContentIntent(getPlayerActivityPendingIntent()); + notification.setWhen(0); + notification.setSmallIcon(R.drawable.ic_antenna); + notification.setOngoing(false); + notification.setOnlyAlertOnce(true); + notification.setPriority(UserPreferences.getNotifyPriority()); + notification.setVisibility(NotificationCompat.VISIBILITY_PUBLIC); + notification.setColor(NotificationCompat.COLOR_DEFAULT); + return notification.build(); + } + + private PendingIntent getPlayerActivityPendingIntent() { + return PendingIntent.getActivity(context, 0, PlaybackService.getPlayerActivityIntent(context), + PendingIntent.FLAG_UPDATE_CURRENT); + } + + private void addActions(NotificationCompat.Builder notification, MediaSessionCompat.Token mediaSessionToken, + PlayerStatus playerStatus, boolean isCasting) { IntList compactActionList = new IntList(); int numActions = 0; // we start and 0 and then increment by 1 for each call to addAction @@ -140,7 +164,7 @@ public class PlaybackServiceNotificationBuilder extends NotificationCompat.Build stopCastingIntent.putExtra(PlaybackService.EXTRA_CAST_DISCONNECT, true); PendingIntent stopCastingPendingIntent = PendingIntent.getService(context, numActions, stopCastingIntent, PendingIntent.FLAG_UPDATE_CURRENT); - addAction(R.drawable.ic_notification_cast_off, + notification.addAction(R.drawable.ic_notification_cast_off, context.getString(R.string.cast_disconnect_label), stopCastingPendingIntent); numActions++; @@ -149,7 +173,8 @@ public class PlaybackServiceNotificationBuilder extends NotificationCompat.Build // always let them rewind PendingIntent rewindButtonPendingIntent = getPendingIntentForMediaAction( KeyEvent.KEYCODE_MEDIA_REWIND, numActions); - addAction(R.drawable.ic_notification_fast_rewind, context.getString(R.string.rewind_label), rewindButtonPendingIntent); + notification.addAction(R.drawable.ic_notification_fast_rewind, context.getString(R.string.rewind_label), + rewindButtonPendingIntent); if (UserPreferences.showRewindOnCompactNotification()) { compactActionList.add(numActions); } @@ -158,14 +183,14 @@ public class PlaybackServiceNotificationBuilder extends NotificationCompat.Build if (playerStatus == PlayerStatus.PLAYING) { PendingIntent pauseButtonPendingIntent = getPendingIntentForMediaAction( KeyEvent.KEYCODE_MEDIA_PAUSE, numActions); - addAction(R.drawable.ic_notification_pause, //pause action + notification.addAction(R.drawable.ic_notification_pause, //pause action context.getString(R.string.pause_label), pauseButtonPendingIntent); compactActionList.add(numActions++); } else { PendingIntent playButtonPendingIntent = getPendingIntentForMediaAction( KeyEvent.KEYCODE_MEDIA_PLAY, numActions); - addAction(R.drawable.ic_notification_play, //play action + notification.addAction(R.drawable.ic_notification_play, //play action context.getString(R.string.play_label), playButtonPendingIntent); compactActionList.add(numActions++); @@ -174,7 +199,8 @@ public class PlaybackServiceNotificationBuilder extends NotificationCompat.Build // ff follows play, then we have skip (if it's present) PendingIntent ffButtonPendingIntent = getPendingIntentForMediaAction( KeyEvent.KEYCODE_MEDIA_FAST_FORWARD, numActions); - addAction(R.drawable.ic_notification_fast_forward, context.getString(R.string.fast_forward_label), ffButtonPendingIntent); + notification.addAction(R.drawable.ic_notification_fast_forward, context.getString(R.string.fast_forward_label), + ffButtonPendingIntent); if (UserPreferences.showFastForwardOnCompactNotification()) { compactActionList.add(numActions); } @@ -183,7 +209,7 @@ public class PlaybackServiceNotificationBuilder extends NotificationCompat.Build if (UserPreferences.isFollowQueue()) { PendingIntent skipButtonPendingIntent = getPendingIntentForMediaAction( KeyEvent.KEYCODE_MEDIA_NEXT, numActions); - addAction(R.drawable.ic_notification_skip, + notification.addAction(R.drawable.ic_notification_skip, context.getString(R.string.skip_episode_label), skipButtonPendingIntent); if (UserPreferences.showSkipOnCompactNotification()) { @@ -194,7 +220,7 @@ public class PlaybackServiceNotificationBuilder extends NotificationCompat.Build PendingIntent stopButtonPendingIntent = getPendingIntentForMediaAction( KeyEvent.KEYCODE_MEDIA_STOP, numActions); - setStyle(new androidx.media.app.NotificationCompat.MediaStyle() + notification.setStyle(new androidx.media.app.NotificationCompat.MediaStyle() .setMediaSession(mediaSessionToken) .setShowActionsInCompactView(compactActionList.toArray()) .setShowCancelButton(true) |