diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 6fd0e7d682f..967b0397573 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -75,6 +75,8 @@ `DownloadNotificationHelper`. * Move creation of dialogs for `TrackSelectionView`s to `TrackSelectionDialogBuilder` and add option to select multiple overrides. +* MediaSessionConnector: Let apps intercept media button events + ([#5179](https://github.com/google/ExoPlayer/issues/5179)). ### 2.9.5 ### diff --git a/extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/MediaSessionConnector.java b/extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/MediaSessionConnector.java index 9074f9e16dc..6d80c1001fd 100644 --- a/extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/MediaSessionConnector.java +++ b/extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/MediaSessionConnector.java @@ -15,6 +15,7 @@ */ package com.google.android.exoplayer2.ext.mediasession; +import android.content.Intent; import android.graphics.Bitmap; import android.net.Uri; import android.os.Bundle; @@ -76,6 +77,9 @@ * is recommended for most use cases. *
  • To enable editing of the media queue, you can set a {@link QueueEditor} by calling {@link * #setQueueEditor(QueueEditor)}. + *
  • A {@link MediaButtonEventHandler} can be set by calling {@link + * #setMediaButtonEventHandler(MediaButtonEventHandler)}. By default media button events are + * handled by {@link MediaSessionCompat.Callback#onMediaButtonEvent(Intent)}. *
  • An {@link ErrorMessageProvider} for providing human readable error messages and * corresponding error codes can be set by calling {@link * #setErrorMessageProvider(ErrorMessageProvider)}. @@ -300,6 +304,21 @@ public interface RatingCallback extends CommandReceiver { void onSetRating(Player player, RatingCompat rating, Bundle extras); } + /** Handles a media button event. */ + public interface MediaButtonEventHandler { + /** + * See {@link MediaSessionCompat.Callback#onMediaButtonEvent(Intent)}. + * + * @param player The {@link Player}. + * @param controlDispatcher A {@link ControlDispatcher} that should be used for dispatching + * changes to the player. + * @param mediaButtonEvent The {@link Intent}. + * @return True if the event was handled, false otherwise. + */ + boolean onMediaButtonEvent( + Player player, ControlDispatcher controlDispatcher, Intent mediaButtonEvent); + } + /** * Provides a {@link PlaybackStateCompat.CustomAction} to be published and handles the action when * sent by a media controller. @@ -357,6 +376,7 @@ public interface MediaMetadataProvider { @Nullable private QueueNavigator queueNavigator; @Nullable private QueueEditor queueEditor; @Nullable private RatingCallback ratingCallback; + @Nullable private MediaButtonEventHandler mediaButtonEventHandler; private long enabledPlaybackActions; private int rewindMs; @@ -432,6 +452,18 @@ public void setControlDispatcher(@Nullable ControlDispatcher controlDispatcher) } } + /** + * Sets the {@link MediaButtonEventHandler}. Pass {@code null} if the media button event should be + * handled by {@link MediaSessionCompat.Callback#onMediaButtonEvent(Intent)}. + * + * @param mediaButtonEventHandler The {@link MediaButtonEventHandler}, or null to let the event be + * handled by {@link MediaSessionCompat.Callback#onMediaButtonEvent(Intent)}. + */ + public void setMediaButtonEventHandler( + @Nullable MediaButtonEventHandler mediaButtonEventHandler) { + this.mediaButtonEventHandler = mediaButtonEventHandler; + } + /** * Sets the enabled playback actions. * @@ -753,6 +785,10 @@ private boolean canDispatchQueueEdit() { return player != null && queueEditor != null; } + private boolean canDispatchMediaButtonEvent() { + return player != null && mediaButtonEventHandler != null; + } + private void stopPlayerForPrepare(boolean playWhenReady) { if (player != null) { player.stop(); @@ -1169,5 +1205,14 @@ public void onRemoveQueueItem(MediaDescriptionCompat description) { queueEditor.onRemoveQueueItem(player, description); } } + + @Override + public boolean onMediaButtonEvent(Intent mediaButtonEvent) { + boolean isHandled = + canDispatchMediaButtonEvent() + && mediaButtonEventHandler.onMediaButtonEvent( + player, controlDispatcher, mediaButtonEvent); + return isHandled || super.onMediaButtonEvent(mediaButtonEvent); + } } }