summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorH. Lehmann <ByteHamster@users.noreply.github.com>2019-10-06 19:42:14 +0200
committerGitHub <noreply@github.com>2019-10-06 19:42:14 +0200
commit0e614f96e994fd4f3ed2e2bf3e628041da34648c (patch)
tree6ffceb6ebda8ee1c5a0cc0e461a135d52f9cbbb2
parentf750e06a1be5c93f7a8cffd49f56a57080583a82 (diff)
parent6f809b47e6a3d2929eaf31830bc0aa2b8abd87bb (diff)
downloadAntennaPod-0e614f96e994fd4f3ed2e2bf3e628041da34648c.zip
Merge pull request #3497 from ByteHamster/position-in-notification
Showing progress in notification
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java103
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceNotificationBuilder.java144
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)