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
This commit is contained in:
Jin Seok Park
2020-12-09 00:44:28 +09:00
parent 09454b278b
commit 258fca377d
5 changed files with 57 additions and 1 deletions

View File

@@ -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);

View File

@@ -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();

View File

@@ -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.
* <p>
* 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.
*

View File

@@ -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;

View File

@@ -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;