Skip to content

Commit ffaa36e

Browse files
committed
Add notification update reason API and allow manual notification updates
Issue: #1833
1 parent 593d3c1 commit ffaa36e

File tree

4 files changed

+180
-25
lines changed

4 files changed

+180
-25
lines changed

libraries/session/src/main/java/androidx/media3/session/DefaultMediaNotificationProvider.java

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -301,7 +301,8 @@ public final MediaNotification createNotification(
301301
MediaSession mediaSession,
302302
ImmutableList<CommandButton> mediaButtonPreferences,
303303
MediaNotification.ActionFactory actionFactory,
304-
Callback onNotificationChangedCallback) {
304+
Callback onNotificationChangedCallback,
305+
@MediaSessionService.NotificationUpdate int reason) {
305306
ensureNotificationChannel();
306307

307308
ImmutableList.Builder<CommandButton> mediaButtonPreferencesWithEnabledCommandButtonsOnly =
@@ -354,7 +355,7 @@ public final MediaNotification createNotification(
354355
} else {
355356
pendingOnBitmapLoadedFutureCallback =
356357
new OnBitmapLoadedFutureCallback(
357-
notificationId, builder, onNotificationChangedCallback);
358+
notificationId, builder, onNotificationChangedCallback, reason);
358359
Futures.addCallback(
359360
bitmapFuture,
360361
pendingOnBitmapLoadedFutureCallback,
@@ -387,7 +388,7 @@ public final MediaNotification createNotification(
387388
.setOngoing(false)
388389
.setGroup(GROUP_KEY)
389390
.build();
390-
return new MediaNotification(notificationId, notification);
391+
return createMediaNotification(notificationId, notification, reason, false);
391392
}
392393

393394
@Override
@@ -408,6 +409,32 @@ public final void setSmallIcon(@DrawableRes int smallIconResourceId) {
408409
this.smallIconResourceId = smallIconResourceId;
409410
}
410411

412+
/**
413+
* Create a {@link MediaNotification} instance.
414+
*
415+
* <p>This method is called each time a new notification is built, and when the large icon
416+
* finishes loading.
417+
*
418+
* <p>Subclasses may override this method to intercept the created {@link Notification} object or
419+
* its ID.
420+
*
421+
* @param notificationId Constructor parameter of {@link MediaNotification}
422+
* @param notification Constructor parameter of {@link MediaNotification}
423+
* @param reason Reason why the notification is being (re)created, useful for metrics or advanced
424+
* customization.
425+
* @param isRebuild true if the notification is being recreated because the album art finished
426+
* loading
427+
* @see MediaNotification#MediaNotification(int, Notification)
428+
* @return The created instance.
429+
*/
430+
protected MediaNotification createMediaNotification(
431+
int notificationId,
432+
Notification notification,
433+
@MediaSessionService.NotificationUpdate int reason,
434+
boolean isRebuild) {
435+
return new MediaNotification(notificationId, notification);
436+
}
437+
411438
/**
412439
* Returns the ordered list of {@linkplain CommandButton command buttons} to be used to build the
413440
* notification.
@@ -640,20 +667,23 @@ private static long getPlaybackStartTimeEpochMs(Player player) {
640667
}
641668
}
642669

643-
private static class OnBitmapLoadedFutureCallback implements FutureCallback<Bitmap> {
670+
private class OnBitmapLoadedFutureCallback implements FutureCallback<Bitmap> {
644671
private final int notificationId;
645672
private final NotificationCompat.Builder builder;
646673
private final Callback onNotificationChangedCallback;
674+
private final @MediaSessionService.NotificationUpdate int reason;
647675

648676
private boolean discarded;
649677

650678
public OnBitmapLoadedFutureCallback(
651679
int notificationId,
652680
NotificationCompat.Builder builder,
653-
Callback onNotificationChangedCallback) {
681+
Callback onNotificationChangedCallback,
682+
@MediaSessionService.NotificationUpdate int reason) {
654683
this.notificationId = notificationId;
655684
this.builder = builder;
656685
this.onNotificationChangedCallback = onNotificationChangedCallback;
686+
this.reason = reason;
657687
}
658688

659689
public void discardIfPending() {
@@ -665,7 +695,7 @@ public void onSuccess(Bitmap result) {
665695
if (!discarded) {
666696
builder.setLargeIcon(result);
667697
onNotificationChangedCallback.onNotificationChanged(
668-
new MediaNotification(notificationId, builder.build()));
698+
createMediaNotification(notificationId, builder.build(), reason, true));
669699
}
670700
}
671701

libraries/session/src/main/java/androidx/media3/session/MediaNotification.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,12 +170,15 @@ interface Callback {
170170
* @param onNotificationChangedCallback A callback that the provider needs to notify when the
171171
* notification has changed and needs to be posted again, for example after a bitmap has
172172
* been loaded asynchronously.
173+
* @param reason Reason why the notification is being (re)created, useful for metrics or
174+
* advanced customization.
173175
*/
174176
MediaNotification createNotification(
175177
MediaSession mediaSession,
176178
ImmutableList<CommandButton> mediaButtonPreferences,
177179
ActionFactory actionFactory,
178-
Callback onNotificationChangedCallback);
180+
Callback onNotificationChangedCallback,
181+
@MediaSessionService.NotificationUpdate int reason);
179182

180183
/**
181184
* Handles a notification's custom command.

libraries/session/src/main/java/androidx/media3/session/MediaNotificationManager.java

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,10 @@ public void setMediaNotificationProvider(MediaNotification.Provider mediaNotific
167167
* @param session A session that needs notification update.
168168
* @param startInForegroundRequired Whether the service is required to start in the foreground.
169169
*/
170-
public void updateNotification(MediaSession session, boolean startInForegroundRequired) {
170+
public void updateNotification(
171+
MediaSession session,
172+
boolean startInForegroundRequired,
173+
@MediaSessionService.NotificationUpdate int reason) {
171174
if (!mediaSessionService.isSessionAdded(session) || !shouldShowNotification(session)) {
172175
removeNotification();
173176
return;
@@ -185,7 +188,7 @@ public void updateNotification(MediaSession session, boolean startInForegroundRe
185188
() -> {
186189
MediaNotification mediaNotification =
187190
this.mediaNotificationProvider.createNotification(
188-
session, mediaButtonPreferences, actionFactory, callback);
191+
session, mediaButtonPreferences, actionFactory, callback, reason);
189192
mainExecutor.execute(
190193
() ->
191194
updateNotificationInternal(
@@ -207,7 +210,8 @@ public void setShowNotificationForIdlePlayer(
207210
List<MediaSession> sessions = mediaSessionService.getSessions();
208211
for (int i = 0; i < sessions.size(); i++) {
209212
mediaSessionService.onUpdateNotificationInternal(
210-
sessions.get(i), /* startInForegroundWhenPaused= */ false);
213+
sessions.get(i), /* startInForegroundWhenPaused= */ false,
214+
MediaSessionService.NOTIFICATION_UPDATE_IDLE_PLAYER_SETTING_CHANGED);
211215
}
212216
}
213217

@@ -217,7 +221,9 @@ public boolean handleMessage(Message msg) {
217221
List<MediaSession> sessions = mediaSessionService.getSessions();
218222
for (int i = 0; i < sessions.size(); i++) {
219223
mediaSessionService.onUpdateNotificationInternal(
220-
sessions.get(i), /* startInForegroundWhenPaused= */ false);
224+
sessions.get(i),
225+
/* startInForegroundWhenPaused= */ false,
226+
MediaSessionService.NOTIFICATION_UPDATE_ENGAGED_TIMEOUT);
221227
}
222228
return true;
223229
}
@@ -262,7 +268,9 @@ private boolean isAnySessionUserEngaged(boolean startInForegroundWhenPaused) {
262268
List<MediaSession> sessions = mediaSessionService.getSessions();
263269
for (int i = 0; i < sessions.size(); i++) {
264270
mediaSessionService.onUpdateNotificationInternal(
265-
sessions.get(i), /* startInForegroundWhenPaused= */ false);
271+
sessions.get(i),
272+
/* startInForegroundWhenPaused= */ false,
273+
MediaSessionService.NOTIFICATION_UPDATE_ENGAGED_TIMEOUT_DISABLED);
266274
}
267275
}
268276
}
@@ -402,22 +410,28 @@ public MediaControllerListener(MediaSessionService mediaSessionService, MediaSes
402410
public void onConnected(boolean shouldShowNotification) {
403411
if (shouldShowNotification) {
404412
mediaSessionService.onUpdateNotificationInternal(
405-
session, /* startInForegroundWhenPaused= */ false);
413+
session,
414+
/* startInForegroundWhenPaused= */ false,
415+
MediaSessionService.NOTIFICATION_UPDATE_CONNECTED);
406416
}
407417
}
408418

409419
@Override
410420
public void onMediaButtonPreferencesChanged(
411421
MediaController controller, List<CommandButton> mediaButtonPreferences) {
412422
mediaSessionService.onUpdateNotificationInternal(
413-
session, /* startInForegroundWhenPaused= */ false);
423+
session,
424+
/* startInForegroundWhenPaused= */ false,
425+
MediaSessionService.NOTIFICATION_UPDATE_BUTTON_PREFERENCES_CHANGED);
414426
}
415427

416428
@Override
417429
public void onAvailableSessionCommandsChanged(
418430
MediaController controller, SessionCommands commands) {
419431
mediaSessionService.onUpdateNotificationInternal(
420-
session, /* startInForegroundWhenPaused= */ false);
432+
session,
433+
/* startInForegroundWhenPaused= */ false,
434+
MediaSessionService.NOTIFICATION_UPDATE_SESSION_COMMANDS_CHANGED);
421435
}
422436

423437
@Override
@@ -438,7 +452,9 @@ public void onDisconnected(MediaController controller) {
438452
}
439453
// We may need to hide the notification.
440454
mediaSessionService.onUpdateNotificationInternal(
441-
session, /* startInForegroundWhenPaused= */ false);
455+
session,
456+
/* startInForegroundWhenPaused= */ false,
457+
MediaSessionService.NOTIFICATION_UPDATE_DISCONNECTED);
442458
}
443459

444460
@Override
@@ -451,7 +467,9 @@ public void onEvents(Player player, Player.Events events) {
451467
Player.EVENT_MEDIA_METADATA_CHANGED,
452468
Player.EVENT_TIMELINE_CHANGED)) {
453469
mediaSessionService.onUpdateNotificationInternal(
454-
session, /* startInForegroundWhenPaused= */ false);
470+
session,
471+
/* startInForegroundWhenPaused= */ false,
472+
MediaSessionService.NOTIFICATION_UPDATE_PLAYER_EVENT);
455473
}
456474
}
457475
}

0 commit comments

Comments
 (0)