From 258fca377dc7e0ddb8469395922d6904159b8ab1 Mon Sep 17 00:00:00 2001 From: Jin Seok Park Date: Wed, 9 Dec 2020 00:44:28 +0900 Subject: [PATCH] Add setMediaButtonBroadcastReceiver API This API will replace the existing setMediaButtonReceiver(PendingIntent) API to address the issue that PendingIntent obejcts should not be persisted over reboots. See go/replace-setmediabuttonreceiver for more details. Bug: 161334442 Test: atest CtsMediaTestCases:android.media.cts.MediaSessionTest Change-Id: I4ece6b8595b5f572426b96fbf06edb34c93eeb50 --- core/api/current.txt | 3 +- .../java/android/media/session/ISession.aidl | 2 ++ .../android/media/session/MediaSession.java | 32 +++++++++++++++++++ .../media/MediaButtonReceiverHolder.java | 5 +++ .../server/media/MediaSessionRecord.java | 16 ++++++++++ 5 files changed, 57 insertions(+), 1 deletion(-) diff --git a/core/api/current.txt b/core/api/current.txt index f49ce1fd48a5b..2ed02c04017dc 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -24225,7 +24225,8 @@ package android.media.session { method public void setCallback(@Nullable android.media.session.MediaSession.Callback, @Nullable android.os.Handler); method public void setExtras(@Nullable android.os.Bundle); method public void setFlags(int); - method public void setMediaButtonReceiver(@Nullable android.app.PendingIntent); + method public void setMediaButtonBroadcastReceiver(@Nullable android.content.ComponentName); + method @Deprecated public void setMediaButtonReceiver(@Nullable android.app.PendingIntent); method public void setMetadata(@Nullable android.media.MediaMetadata); method public void setPlaybackState(@Nullable android.media.session.PlaybackState); method public void setPlaybackToLocal(android.media.AudioAttributes); diff --git a/media/java/android/media/session/ISession.aidl b/media/java/android/media/session/ISession.aidl index 77f7b54368f85..31fb8d03c4a06 100644 --- a/media/java/android/media/session/ISession.aidl +++ b/media/java/android/media/session/ISession.aidl @@ -16,6 +16,7 @@ package android.media.session; import android.app.PendingIntent; +import android.content.ComponentName; import android.content.pm.ParceledListSlice; import android.media.AudioAttributes; import android.media.MediaMetadata; @@ -35,6 +36,7 @@ interface ISession { void setFlags(int flags); void setActive(boolean active); void setMediaButtonReceiver(in PendingIntent mbr); + void setMediaButtonBroadcastReceiver(in ComponentName broadcastReceiver); void setLaunchPendingIntent(in PendingIntent pi); void destroySession(); diff --git a/media/java/android/media/session/MediaSession.java b/media/java/android/media/session/MediaSession.java index 14b236890e4a4..24118b086c249 100644 --- a/media/java/android/media/session/MediaSession.java +++ b/media/java/android/media/session/MediaSession.java @@ -23,6 +23,7 @@ import android.annotation.SystemApi; import android.app.Activity; import android.app.PendingIntent; import android.compat.annotation.UnsupportedAppUsage; +import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.media.AudioAttributes; @@ -131,6 +132,7 @@ public final class MediaSession { public @interface SessionFlags { } private final Object mLock = new Object(); + private Context mContext; private final int mMaxBitmapSize; private final Token mSessionToken; @@ -194,6 +196,7 @@ public final class MediaSession { + "parcelables"); } + mContext = context; mMaxBitmapSize = context.getResources().getDimensionPixelSize( com.android.internal.R.dimen.config_mediaMetadataBitmapMaxSize); mCbStub = new CallbackStub(this); @@ -277,7 +280,10 @@ public final class MediaSession { * * @param mbr The {@link PendingIntent} to send the media button event to. * @see PendingIntent#getActivity + * + * @deprecated Use {@link #setMediaButtonBroadcastReceiver(ComponentName)} instead. */ + @Deprecated public void setMediaButtonReceiver(@Nullable PendingIntent mbr) { try { mBinder.setMediaButtonReceiver(mbr); @@ -286,6 +292,32 @@ public final class MediaSession { } } + /** + * Set the component name of the manifest-declared {@link android.content.BroadcastReceiver} + * class that should receive media buttons. This allows restarting playback after the session + * has been stopped. If your app is started in this way an {@link Intent#ACTION_MEDIA_BUTTON} + * intent will be sent to the broadcast receiver. + *

+ * Note: The given {@link android.content.BroadcastReceiver} should belong to the same package + * as the context that was given when creating {@link MediaSession}. + * + * @param broadcastReceiver the component name of the BroadcastReceiver class + */ + public void setMediaButtonBroadcastReceiver(@Nullable ComponentName broadcastReceiver) { + try { + if (broadcastReceiver != null) { + if (!TextUtils.equals(broadcastReceiver.getPackageName(), + mContext.getPackageName())) { + throw new IllegalArgumentException("broadcastReceiver should belong to the same" + + " package as the context given when creating MediaSession."); + } + } + mBinder.setMediaButtonBroadcastReceiver(broadcastReceiver); + } catch (RemoteException e) { + Log.wtf(TAG, "Failure in setMediaButtonBroadcastReceiver.", e); + } + } + /** * Set any flags for the session. * diff --git a/services/core/java/com/android/server/media/MediaButtonReceiverHolder.java b/services/core/java/com/android/server/media/MediaButtonReceiverHolder.java index 0a4d17f20aec3..e2e5046d98bf3 100644 --- a/services/core/java/com/android/server/media/MediaButtonReceiverHolder.java +++ b/services/core/java/com/android/server/media/MediaButtonReceiverHolder.java @@ -141,6 +141,11 @@ final class MediaButtonReceiverHolder { packageName != null ? packageName : ""); } + public static MediaButtonReceiverHolder create(int userId, ComponentName broadcastReceiver) { + return new MediaButtonReceiverHolder(userId, null, broadcastReceiver, + COMPONENT_TYPE_BROADCAST); + } + private MediaButtonReceiverHolder(int userId, PendingIntent pendingIntent, ComponentName componentName, @ComponentType int componentType) { mUserId = userId; diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java index ea6e7d7d0bf60..ae58d4c40622a 100644 --- a/services/core/java/com/android/server/media/MediaSessionRecord.java +++ b/services/core/java/com/android/server/media/MediaSessionRecord.java @@ -18,6 +18,7 @@ package com.android.server.media; import android.annotation.Nullable; import android.app.PendingIntent; +import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.pm.ParceledListSlice; @@ -857,6 +858,21 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR } } + @Override + public void setMediaButtonBroadcastReceiver(ComponentName receiver) throws RemoteException { + final long token = Binder.clearCallingIdentity(); + try { + if ((mPolicies & SessionPolicyProvider.SESSION_POLICY_IGNORE_BUTTON_RECEIVER) + != 0) { + return; + } + mMediaButtonReceiverHolder = MediaButtonReceiverHolder.create(mUserId, receiver); + mService.onMediaButtonReceiverChanged(MediaSessionRecord.this); + } finally { + Binder.restoreCallingIdentity(token); + } + } + @Override public void setLaunchPendingIntent(PendingIntent pi) throws RemoteException { mLaunchIntent = pi;