diff options
17 files changed, 2080 insertions, 272 deletions
diff --git a/api/current.txt b/api/current.txt index 6122e5208985..d37841689332 100644 --- a/api/current.txt +++ b/api/current.txt @@ -27286,21 +27286,6 @@ package android.media.projection { package android.media.session { - public final class ControllerCallbackLink implements android.os.Parcelable { - method public int describeContents(); - method @NonNull public android.os.IBinder getBinder(); - method public void notifyEvent(@NonNull String, @Nullable android.os.Bundle); - method public void notifyExtrasChanged(@Nullable android.os.Bundle); - method public void notifyMetadataChanged(@Nullable android.media.MediaMetadata); - method public void notifyPlaybackStateChanged(@Nullable android.media.session.PlaybackState); - method public void notifyQueueChanged(@Nullable java.util.List<android.media.session.MediaSession.QueueItem>); - method public void notifyQueueTitleChanged(@Nullable CharSequence); - method public void notifySessionDestroyed(); - method public void notifyVolumeInfoChanged(@NonNull android.media.session.MediaController.PlaybackInfo); - method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator<android.media.session.ControllerCallbackLink> CREATOR; - } - public final class MediaController { ctor public MediaController(@NonNull android.content.Context, @NonNull android.media.session.MediaSession.Token); method public void adjustVolume(int, int); @@ -27535,36 +27520,6 @@ package android.media.session { method public android.media.session.PlaybackState.CustomAction.Builder setExtras(android.os.Bundle); } - public final class SessionCallbackLink implements android.os.Parcelable { - method public int describeContents(); - method @NonNull public android.os.IBinder getBinder(); - method public void notifyAdjustVolume(@NonNull String, int, int, @NonNull android.media.session.ControllerCallbackLink, int); - method public void notifyCommand(@NonNull String, int, int, @NonNull android.media.session.ControllerCallbackLink, @NonNull String, @Nullable android.os.Bundle, @Nullable android.os.ResultReceiver); - method public void notifyCustomAction(@NonNull String, int, int, @NonNull android.media.session.ControllerCallbackLink, @NonNull String, @Nullable android.os.Bundle); - method public void notifyFastForward(@NonNull String, int, int, @NonNull android.media.session.ControllerCallbackLink); - method public void notifyMediaButton(@NonNull String, int, int, @NonNull android.content.Intent, int, @Nullable android.os.ResultReceiver); - method public void notifyMediaButtonFromController(@NonNull String, int, int, @NonNull android.media.session.ControllerCallbackLink, @NonNull android.content.Intent); - method public void notifyNext(@NonNull String, int, int, @NonNull android.media.session.ControllerCallbackLink); - method public void notifyPause(@NonNull String, int, int, @NonNull android.media.session.ControllerCallbackLink); - method public void notifyPlay(@NonNull String, int, int, @NonNull android.media.session.ControllerCallbackLink); - method public void notifyPlayFromMediaId(@NonNull String, int, int, @NonNull android.media.session.ControllerCallbackLink, @NonNull String, @Nullable android.os.Bundle); - method public void notifyPlayFromSearch(@NonNull String, int, int, @NonNull android.media.session.ControllerCallbackLink, @NonNull String, @Nullable android.os.Bundle); - method public void notifyPlayFromUri(@NonNull String, int, int, @NonNull android.media.session.ControllerCallbackLink, @NonNull android.net.Uri, @Nullable android.os.Bundle); - method public void notifyPrepare(@NonNull String, int, int, @NonNull android.media.session.ControllerCallbackLink); - method public void notifyPrepareFromMediaId(@NonNull String, int, int, @NonNull android.media.session.ControllerCallbackLink, @NonNull String, @Nullable android.os.Bundle); - method public void notifyPrepareFromSearch(@NonNull String, int, int, @NonNull android.media.session.ControllerCallbackLink, @NonNull String, @Nullable android.os.Bundle); - method public void notifyPrepareFromUri(@NonNull String, int, int, @NonNull android.media.session.ControllerCallbackLink, @NonNull android.net.Uri, @Nullable android.os.Bundle); - method public void notifyPrevious(@NonNull String, int, int, @NonNull android.media.session.ControllerCallbackLink); - method public void notifyRate(@NonNull String, int, int, @NonNull android.media.session.ControllerCallbackLink, @NonNull android.media.Rating); - method public void notifyRewind(@NonNull String, int, int, @NonNull android.media.session.ControllerCallbackLink); - method public void notifySeekTo(@NonNull String, int, int, @NonNull android.media.session.ControllerCallbackLink, long); - method public void notifySetVolumeTo(@NonNull String, int, int, @NonNull android.media.session.ControllerCallbackLink, int); - method public void notifySkipToTrack(@NonNull String, int, int, @NonNull android.media.session.ControllerCallbackLink, long); - method public void notifyStop(@NonNull String, int, int, @NonNull android.media.session.ControllerCallbackLink); - method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator<android.media.session.SessionCallbackLink> CREATOR; - } - } package android.media.tv { diff --git a/api/system-current.txt b/api/system-current.txt index ce0ef384ffdd..810b237e610c 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -3448,7 +3448,20 @@ package android.media.audiopolicy { package android.media.session { public final class ControllerCallbackLink implements android.os.Parcelable { - ctor public ControllerCallbackLink(@NonNull android.media.session.ControllerCallbackLink.CallbackStub); + ctor public ControllerCallbackLink(@NonNull android.content.Context, @NonNull android.media.session.ControllerCallbackLink.CallbackStub); + ctor public ControllerCallbackLink(android.os.IBinder); + method public int describeContents(); + method @NonNull public android.os.IBinder getBinder(); + method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifyEvent(@NonNull String, @Nullable android.os.Bundle); + method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifyExtrasChanged(@Nullable android.os.Bundle); + method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifyMetadataChanged(@Nullable android.media.MediaMetadata); + method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifyPlaybackStateChanged(@Nullable android.media.session.PlaybackState); + method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifyQueueChanged(@Nullable java.util.List<android.media.session.MediaSession.QueueItem>); + method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifyQueueTitleChanged(@Nullable CharSequence); + method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifySessionDestroyed(); + method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifyVolumeInfoChanged(@NonNull android.media.session.MediaController.PlaybackInfo); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.media.session.ControllerCallbackLink> CREATOR; } public abstract static class ControllerCallbackLink.CallbackStub { @@ -3463,6 +3476,60 @@ package android.media.session { method public void onVolumeInfoChanged(@NonNull android.media.session.MediaController.PlaybackInfo); } + public final class ControllerLink implements android.os.Parcelable { + ctor public ControllerLink(@NonNull android.media.session.ControllerLink.ControllerStub); + ctor public ControllerLink(android.os.IBinder); + method public int describeContents(); + method @NonNull public android.os.IBinder getBinder(); + method @Nullable public android.os.Bundle getExtras(); + method @Nullable public android.media.MediaMetadata getMetadata(); + method @Nullable public android.media.session.PlaybackState getPlaybackState(); + method @Nullable public java.util.List<android.media.session.MediaSession.QueueItem> getQueue(); + method @Nullable public CharSequence getQueueTitle(); + method public int getRatingType(); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.media.session.ControllerLink> CREATOR; + } + + public abstract static class ControllerLink.ControllerStub { + ctor public ControllerLink.ControllerStub(); + method public void adjustVolume(@NonNull String, @NonNull String, @NonNull android.media.session.ControllerCallbackLink, boolean, int, int); + method public void fastForward(@NonNull String, @NonNull android.media.session.ControllerCallbackLink); + method @Nullable public android.os.Bundle getExtras(); + method public long getFlags(); + method @Nullable public android.app.PendingIntent getLaunchPendingIntent(); + method @Nullable public android.media.MediaMetadata getMetadata(); + method @NonNull public String getPackageName(); + method @Nullable public android.media.session.PlaybackState getPlaybackState(); + method @Nullable public java.util.List<android.media.session.MediaSession.QueueItem> getQueue(); + method @Nullable public CharSequence getQueueTitle(); + method public int getRatingType(); + method @NonNull public String getTag(); + method @NonNull public android.media.session.MediaController.PlaybackInfo getVolumeAttributes(); + method public void next(@NonNull String, @NonNull android.media.session.ControllerCallbackLink); + method public void pause(@NonNull String, @NonNull android.media.session.ControllerCallbackLink); + method public void play(@NonNull String, @NonNull android.media.session.ControllerCallbackLink); + method public void playFromMediaId(@NonNull String, @NonNull android.media.session.ControllerCallbackLink, @NonNull String, @Nullable android.os.Bundle); + method public void playFromSearch(@NonNull String, @NonNull android.media.session.ControllerCallbackLink, @NonNull String, @Nullable android.os.Bundle); + method public void playFromUri(@NonNull String, @NonNull android.media.session.ControllerCallbackLink, @NonNull android.net.Uri, @Nullable android.os.Bundle); + method public void prepare(@NonNull String, @NonNull android.media.session.ControllerCallbackLink); + method public void prepareFromMediaId(@NonNull String, @NonNull android.media.session.ControllerCallbackLink, @NonNull String, @Nullable android.os.Bundle); + method public void prepareFromSearch(@NonNull String, @NonNull android.media.session.ControllerCallbackLink, @NonNull String, @Nullable android.os.Bundle); + method public void prepareFromUri(@NonNull String, @NonNull android.media.session.ControllerCallbackLink, @NonNull android.net.Uri, @Nullable android.os.Bundle); + method public void previous(@NonNull String, @NonNull android.media.session.ControllerCallbackLink); + method public void rate(@NonNull String, @NonNull android.media.session.ControllerCallbackLink, @NonNull android.media.Rating); + method public void registerCallback(@NonNull String, @NonNull android.media.session.ControllerCallbackLink); + method public void rewind(@NonNull String, @NonNull android.media.session.ControllerCallbackLink); + method public void seekTo(@NonNull String, @NonNull android.media.session.ControllerCallbackLink, long); + method public void sendCommand(@NonNull String, @NonNull android.media.session.ControllerCallbackLink, @NonNull String, @Nullable android.os.Bundle, @Nullable android.os.ResultReceiver); + method public void sendCustomAction(@NonNull String, @NonNull android.media.session.ControllerCallbackLink, @NonNull String, @Nullable android.os.Bundle); + method public boolean sendMediaButton(@NonNull String, @NonNull android.media.session.ControllerCallbackLink, boolean, @NonNull android.view.KeyEvent); + method public void setVolumeTo(@NonNull String, @NonNull String, @NonNull android.media.session.ControllerCallbackLink, int, int); + method public void skipToQueueItem(@NonNull String, @NonNull android.media.session.ControllerCallbackLink, long); + method public void stop(@NonNull String, @NonNull android.media.session.ControllerCallbackLink); + method public void unregisterCallback(@NonNull android.media.session.ControllerCallbackLink); + } + public final class MediaSessionManager { method @RequiresPermission(android.Manifest.permission.SET_MEDIA_KEY_LISTENER) public void setOnMediaKeyListener(android.media.session.MediaSessionManager.OnMediaKeyListener, @Nullable android.os.Handler); method @RequiresPermission(android.Manifest.permission.SET_VOLUME_KEY_LONG_PRESS_LISTENER) public void setOnVolumeKeyLongPressListener(android.media.session.MediaSessionManager.OnVolumeKeyLongPressListener, @Nullable android.os.Handler); @@ -3476,6 +3543,66 @@ package android.media.session { method public void onVolumeKeyLongPress(android.view.KeyEvent); } + public final class SessionCallbackLink implements android.os.Parcelable { + ctor public SessionCallbackLink(android.os.IBinder); + method public int describeContents(); + method @NonNull public android.os.IBinder getBinder(); + method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifyAdjustVolume(@NonNull String, int, int, @NonNull android.media.session.ControllerCallbackLink, int); + method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifyCommand(@NonNull String, int, int, @NonNull android.media.session.ControllerCallbackLink, @NonNull String, @Nullable android.os.Bundle, @Nullable android.os.ResultReceiver); + method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifyCustomAction(@NonNull String, int, int, @NonNull android.media.session.ControllerCallbackLink, @NonNull String, @Nullable android.os.Bundle); + method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifyFastForward(@NonNull String, int, int, @NonNull android.media.session.ControllerCallbackLink); + method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifyMediaButton(@NonNull String, int, int, @NonNull android.content.Intent, int, @Nullable android.os.ResultReceiver); + method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifyMediaButtonFromController(@NonNull String, int, int, @NonNull android.media.session.ControllerCallbackLink, @NonNull android.content.Intent); + method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifyNext(@NonNull String, int, int, @NonNull android.media.session.ControllerCallbackLink); + method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifyPause(@NonNull String, int, int, @NonNull android.media.session.ControllerCallbackLink); + method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifyPlay(@NonNull String, int, int, @NonNull android.media.session.ControllerCallbackLink); + method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifyPlayFromMediaId(@NonNull String, int, int, @NonNull android.media.session.ControllerCallbackLink, @NonNull String, @Nullable android.os.Bundle); + method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifyPlayFromSearch(@NonNull String, int, int, @NonNull android.media.session.ControllerCallbackLink, @NonNull String, @Nullable android.os.Bundle); + method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifyPlayFromUri(@NonNull String, int, int, @NonNull android.media.session.ControllerCallbackLink, @NonNull android.net.Uri, @Nullable android.os.Bundle); + method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifyPrepare(@NonNull String, int, int, @NonNull android.media.session.ControllerCallbackLink); + method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifyPrepareFromMediaId(@NonNull String, int, int, @NonNull android.media.session.ControllerCallbackLink, @NonNull String, @Nullable android.os.Bundle); + method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifyPrepareFromSearch(@NonNull String, int, int, @NonNull android.media.session.ControllerCallbackLink, @NonNull String, @Nullable android.os.Bundle); + method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifyPrepareFromUri(@NonNull String, int, int, @NonNull android.media.session.ControllerCallbackLink, @NonNull android.net.Uri, @Nullable android.os.Bundle); + method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifyPrevious(@NonNull String, int, int, @NonNull android.media.session.ControllerCallbackLink); + method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifyRate(@NonNull String, int, int, @NonNull android.media.session.ControllerCallbackLink, @NonNull android.media.Rating); + method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifyRewind(@NonNull String, int, int, @NonNull android.media.session.ControllerCallbackLink); + method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifySeekTo(@NonNull String, int, int, @NonNull android.media.session.ControllerCallbackLink, long); + method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifySetVolumeTo(@NonNull String, int, int, @NonNull android.media.session.ControllerCallbackLink, int); + method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifySkipToTrack(@NonNull String, int, int, @NonNull android.media.session.ControllerCallbackLink, long); + method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifyStop(@NonNull String, int, int, @NonNull android.media.session.ControllerCallbackLink); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.media.session.SessionCallbackLink> CREATOR; + } + + public final class SessionLink implements android.os.Parcelable { + ctor public SessionLink(@NonNull android.media.session.SessionLink.SessionStub); + ctor public SessionLink(android.os.IBinder); + method public int describeContents(); + method @NonNull public android.os.IBinder getBinder(); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.media.session.SessionLink> CREATOR; + } + + public abstract static class SessionLink.SessionStub { + ctor public SessionLink.SessionStub(); + method public void destroySession(); + method @NonNull public android.media.session.ControllerLink getController(); + method public void sendEvent(@NonNull String, @Nullable android.os.Bundle); + method public void setActive(boolean); + method public void setCurrentVolume(int); + method public void setExtras(@Nullable android.os.Bundle); + method public void setFlags(int); + method public void setLaunchPendingIntent(@Nullable android.app.PendingIntent); + method public void setMediaButtonReceiver(@Nullable android.app.PendingIntent); + method public void setMetadata(@Nullable android.media.MediaMetadata, long, @Nullable String); + method public void setPlaybackState(@Nullable android.media.session.PlaybackState); + method public void setPlaybackToLocal(@NonNull android.media.AudioAttributes); + method public void setPlaybackToRemote(int, int); + method public void setQueue(@Nullable java.util.List<android.media.session.MediaSession.QueueItem>); + method public void setQueueTitle(@Nullable CharSequence); + method public void setRatingType(int); + } + } package android.media.soundtrigger { diff --git a/media/java/android/media/IRemoteVolumeController.aidl b/media/java/android/media/IRemoteVolumeController.aidl index e4a4a423800b..a591c1119aeb 100644 --- a/media/java/android/media/IRemoteVolumeController.aidl +++ b/media/java/android/media/IRemoteVolumeController.aidl @@ -25,8 +25,8 @@ import android.media.session.ISessionController; * @hide */ oneway interface IRemoteVolumeController { - void remoteVolumeChanged(ISessionController session, int flags); + void remoteVolumeChanged(in ISessionController session, int flags); // sets the default session to use with the slider, replaces remoteSliderVisibility // on IVolumeController - void updateRemoteController(ISessionController session); + void updateRemoteController(in ISessionController session); } diff --git a/media/java/android/media/session/ControllerCallbackLink.java b/media/java/android/media/session/ControllerCallbackLink.java index a143c9b98ff3..95e19d20e57d 100644 --- a/media/java/android/media/session/ControllerCallbackLink.java +++ b/media/java/android/media/session/ControllerCallbackLink.java @@ -16,35 +16,41 @@ package android.media.session; +import android.Manifest; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.RequiresPermission; import android.annotation.SystemApi; +import android.content.Context; +import android.content.pm.PackageManager; import android.media.MediaMetadata; import android.media.session.MediaController.PlaybackInfo; import android.media.session.MediaSession.QueueItem; +import android.os.Binder; import android.os.Bundle; import android.os.IBinder; import android.os.Parcel; import android.os.Parcelable; +import android.os.Process; import android.os.RemoteException; import java.util.List; /** * Handles incoming commands to {@link MediaController.Callback}. - * <p> - * This API is not generally intended for third party application developers. + * @hide */ +@SystemApi public final class ControllerCallbackLink implements Parcelable { + final Context mContext; final CallbackStub mCallbackStub; final ISessionControllerCallback mIControllerCallback; /** * Constructor for stub (Callee) - * @hide */ - @SystemApi - public ControllerCallbackLink(@NonNull CallbackStub callbackStub) { + public ControllerCallbackLink(@NonNull Context context, @NonNull CallbackStub callbackStub) { + mContext = context; mCallbackStub = callbackStub; mIControllerCallback = new CallbackStubProxy(); } @@ -52,14 +58,16 @@ public final class ControllerCallbackLink implements Parcelable { /** * Constructor for interface (Caller) */ - ControllerCallbackLink(Parcel in) { + public ControllerCallbackLink(IBinder binder) { + mContext = null; mCallbackStub = null; - mIControllerCallback = ISessionControllerCallback.Stub.asInterface(in.readStrongBinder()); + mIControllerCallback = ISessionControllerCallback.Stub.asInterface(binder); } /** * Notify controller that the connected session is destroyed. */ + @RequiresPermission(Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifySessionDestroyed() { try { mIControllerCallback.notifySessionDestroyed(); @@ -74,6 +82,7 @@ public final class ControllerCallbackLink implements Parcelable { * @param event the name of the event * @param extras the extras included with the event */ + @RequiresPermission(Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifyEvent(@NonNull String event, @Nullable Bundle extras) { try { mIControllerCallback.notifyEvent(event, extras); @@ -87,6 +96,7 @@ public final class ControllerCallbackLink implements Parcelable { * * @param state the new playback state */ + @RequiresPermission(Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifyPlaybackStateChanged(@Nullable PlaybackState state) { try { mIControllerCallback.notifyPlaybackStateChanged(state); @@ -100,6 +110,7 @@ public final class ControllerCallbackLink implements Parcelable { * * @param metadata the new metadata */ + @RequiresPermission(Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifyMetadataChanged(@Nullable MediaMetadata metadata) { try { mIControllerCallback.notifyMetadataChanged(metadata); @@ -113,6 +124,7 @@ public final class ControllerCallbackLink implements Parcelable { * * @param queue the new queue */ + @RequiresPermission(Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifyQueueChanged(@Nullable List<QueueItem> queue) { try { mIControllerCallback.notifyQueueChanged(queue); @@ -126,6 +138,7 @@ public final class ControllerCallbackLink implements Parcelable { * * @param title the new queue title */ + @RequiresPermission(Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifyQueueTitleChanged(@Nullable CharSequence title) { try { mIControllerCallback.notifyQueueTitleChanged(title); @@ -139,6 +152,7 @@ public final class ControllerCallbackLink implements Parcelable { * * @param extras the new extras */ + @RequiresPermission(Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifyExtrasChanged(@Nullable Bundle extras) { try { mIControllerCallback.notifyExtrasChanged(extras); @@ -152,6 +166,7 @@ public final class ControllerCallbackLink implements Parcelable { * * @param info the new playback info */ + @RequiresPermission(Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifyVolumeInfoChanged(@NonNull PlaybackInfo info) { try { mIControllerCallback.notifyVolumeInfoChanged(info); @@ -180,7 +195,7 @@ public final class ControllerCallbackLink implements Parcelable { new Parcelable.Creator<ControllerCallbackLink>() { @Override public ControllerCallbackLink createFromParcel(Parcel in) { - return new ControllerCallbackLink(in); + return new ControllerCallbackLink(in.readStrongBinder()); } @Override @@ -191,9 +206,7 @@ public final class ControllerCallbackLink implements Parcelable { /** * Class for Stub implementation - * @hide */ - @SystemApi public abstract static class CallbackStub { /** Stub method for ISessionControllerCallback.notifySessionDestroyed */ public void onSessionDestroyed() { @@ -241,22 +254,46 @@ public final class ControllerCallbackLink implements Parcelable { @Override public void notifyPlaybackStateChanged(PlaybackState state) { - mCallbackStub.onPlaybackStateChanged(state); + ensureMediasControlPermission(); + final long token = Binder.clearCallingIdentity(); + try { + mCallbackStub.onPlaybackStateChanged(state); + } finally { + Binder.restoreCallingIdentity(token); + } } @Override public void notifyMetadataChanged(MediaMetadata metadata) { - mCallbackStub.onMetadataChanged(metadata); + ensureMediasControlPermission(); + final long token = Binder.clearCallingIdentity(); + try { + mCallbackStub.onMetadataChanged(metadata); + } finally { + Binder.restoreCallingIdentity(token); + } } @Override public void notifyQueueChanged(List<QueueItem> queue) { - mCallbackStub.onQueueChanged(queue); + ensureMediasControlPermission(); + final long token = Binder.clearCallingIdentity(); + try { + mCallbackStub.onQueueChanged(queue); + } finally { + Binder.restoreCallingIdentity(token); + } } @Override public void notifyQueueTitleChanged(CharSequence title) { - mCallbackStub.onQueueTitleChanged(title); + ensureMediasControlPermission(); + final long token = Binder.clearCallingIdentity(); + try { + mCallbackStub.onQueueTitleChanged(title); + } finally { + Binder.restoreCallingIdentity(token); + } } @Override @@ -266,7 +303,31 @@ public final class ControllerCallbackLink implements Parcelable { @Override public void notifyVolumeInfoChanged(PlaybackInfo info) { - mCallbackStub.onVolumeInfoChanged(info); + ensureMediasControlPermission(); + final long token = Binder.clearCallingIdentity(); + try { + mCallbackStub.onVolumeInfoChanged(info); + } finally { + Binder.restoreCallingIdentity(token); + } + } + + private void ensureMediasControlPermission() { + // Allow API calls from the System UI + if (mContext.checkCallingPermission(android.Manifest.permission.STATUS_BAR_SERVICE) + == PackageManager.PERMISSION_GRANTED) { + return; + } + + // Check if it's system server or has MEDIA_CONTENT_CONTROL. + // Note that system server doesn't have MEDIA_CONTENT_CONTROL, so we need extra + // check here. + if (getCallingUid() == Process.SYSTEM_UID || mContext.checkCallingPermission( + android.Manifest.permission.MEDIA_CONTENT_CONTROL) + == PackageManager.PERMISSION_GRANTED) { + return; + } + throw new SecurityException("Must hold the MEDIA_CONTENT_CONTROL permission."); } } } diff --git a/media/java/android/media/session/ControllerLink.aidl b/media/java/android/media/session/ControllerLink.aidl new file mode 100644 index 000000000000..532df59d16cf --- /dev/null +++ b/media/java/android/media/session/ControllerLink.aidl @@ -0,0 +1,19 @@ +/* + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.media.session; + +parcelable ControllerLink; diff --git a/media/java/android/media/session/ControllerLink.java b/media/java/android/media/session/ControllerLink.java new file mode 100644 index 000000000000..df1d6497b9e6 --- /dev/null +++ b/media/java/android/media/session/ControllerLink.java @@ -0,0 +1,983 @@ +/* + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.media.session; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.SystemApi; +import android.app.PendingIntent; +import android.media.MediaMetadata; +import android.media.Rating; +import android.media.session.MediaController.PlaybackInfo; +import android.net.Uri; +import android.os.Bundle; +import android.os.IBinder; +import android.os.Parcel; +import android.os.Parcelable; +import android.os.RemoteException; +import android.os.ResultReceiver; +import android.view.KeyEvent; + +import java.util.List; + +/** + * Handles incoming commands from {@link MediaController}. + * @hide + */ +@SystemApi +public final class ControllerLink implements Parcelable { + public static final Parcelable.Creator<ControllerLink> CREATOR = + new Parcelable.Creator<ControllerLink>() { + @Override + public ControllerLink createFromParcel(Parcel in) { + return new ControllerLink(in.readStrongBinder()); + } + + @Override + public ControllerLink[] newArray(int size) { + return new ControllerLink[size]; + } + }; + + final ControllerStub mControllerStub; + final ISessionController mISessionController; + + /** + * Constructor for stub (Callee) + */ + public ControllerLink(@NonNull ControllerStub controllerStub) { + mControllerStub = controllerStub; + mISessionController = new StubProxy(); + } + + /** + * Constructor for interface (Caller) + */ + public ControllerLink(IBinder binder) { + mControllerStub = null; + mISessionController = ISessionController.Stub.asInterface(binder); + } + + /** + * Tell system that a controller sends a command. + * + * @param packageName the package name of the controller + * @param caller the {@link ControllerCallbackLink} of the controller + * @param command the name of the command + * @param args the arguments included with the command + * @param cb the result receiver for getting the result of the command + */ + void sendCommand(@NonNull String packageName, @NonNull ControllerCallbackLink caller, + @NonNull String command, @Nullable Bundle args, @Nullable ResultReceiver cb) { + try { + mISessionController.sendCommand(packageName, caller, command, args, cb); + } catch (RemoteException e) { + throw new RuntimeException(e); + } + } + + /** + * Tell system that a controller sends a media button event. + * + * @param packageName the package name of the controller + * @param caller the {@link ControllerCallbackLink} of the controller + * @param asSystemService whether this event should be considered as from system service + * @param mediaButton the media button key event + */ + boolean sendMediaButton(@NonNull String packageName, + @NonNull ControllerCallbackLink caller, boolean asSystemService, + @NonNull KeyEvent mediaButton) { + try { + return mISessionController.sendMediaButton(packageName, caller, asSystemService, + mediaButton); + } catch (RemoteException e) { + throw new RuntimeException(e); + } + } + + /** + * Registers a controller callback link to the system. + * + * @param packageName the package name of the controller + * @param cb the controller callback link to register + */ + void registerCallback(@NonNull String packageName, @NonNull ControllerCallbackLink cb) { + try { + mISessionController.registerCallback(packageName, cb); + } catch (RemoteException e) { + throw new RuntimeException(e); + } + } + + /** + * Unregisters a controller callback link from the system. + * + * @param cb the controller callback link to register + */ + void unregisterCallback(@NonNull ControllerCallbackLink cb) { + try { + mISessionController.unregisterCallback(cb); + } catch (RemoteException e) { + throw new RuntimeException(e); + } + } + + /** + * Gets the package name of the connected session. + */ + @NonNull + String getPackageName() { + try { + return mISessionController.getPackageName(); + } catch (RemoteException e) { + throw new RuntimeException(e); + } + } + + /** + * Gets the tag of the connected session. + */ + @NonNull + String getTag() { + try { + return mISessionController.getTag(); + } catch (RemoteException e) { + throw new RuntimeException(e); + } + } + + /** + * Gets the {@link PendingIntent} for launching UI of the connected session. + */ + @Nullable + PendingIntent getLaunchPendingIntent() { + try { + return mISessionController.getLaunchPendingIntent(); + } catch (RemoteException e) { + throw new RuntimeException(e); + } + } + + /** + * Gets the flags of the connected session. + */ + long getFlags() { + try { + return mISessionController.getFlags(); + } catch (RemoteException e) { + throw new RuntimeException(e); + } + } + + /** + * Gets the volume attributes of the connected session. + */ + @NonNull + PlaybackInfo getVolumeAttributes() { + try { + return mISessionController.getVolumeAttributes(); + } catch (RemoteException e) { + throw new RuntimeException(e); + } + } + + /** + * Tell system that a controller requests adjusting the volume. + * + * @param packageName the package name of the controller + * @param opPackageName the op package name of this request + * @param caller the {@link ControllerCallbackLink} of the controller + * @param asSystemService whether this event should be considered as from system service + * @param direction the direction to adjust the volume in + * @param flags the flags with this volume change request + */ + void adjustVolume(@NonNull String packageName, @NonNull String opPackageName, + @NonNull ControllerCallbackLink caller, boolean asSystemService, int direction, + int flags) { + try { + mISessionController.adjustVolume(packageName, opPackageName, caller, asSystemService, + direction, flags); + } catch (RemoteException e) { + throw new RuntimeException(e); + } + } + + /** + * Tell system that a controller requests setting the volume. + * + * @param packageName the package name of the controller + * @param opPackageName the op package name of this request + * @param caller the {@link ControllerCallbackLink} of the controller + * @param flags the flags with this volume change request + */ + void setVolumeTo(@NonNull String packageName, @NonNull String opPackageName, + @NonNull ControllerCallbackLink caller, int value, int flags) { + try { + mISessionController.setVolumeTo(packageName, opPackageName, caller, value, flags); + } catch (RemoteException e) { + throw new RuntimeException(e); + } + } + + /** + * Tell system that a controller requests preparing media. + * + * @param packageName the package name of the controller + * @param caller the {@link ControllerCallbackLink} of the controller + */ + void prepare(@NonNull String packageName, @NonNull ControllerCallbackLink caller) { + try { + mISessionController.prepare(packageName, caller); + } catch (RemoteException e) { + throw new RuntimeException(e); + } + } + + /** + * Tell system that a controller requests preparing media from given media ID. + * + * @param packageName the package name of the controller + * @param caller the {@link ControllerCallbackLink} of the controller + * @param mediaId the ID of the media + * @param extras the extras included with this request. + */ + void prepareFromMediaId(@NonNull String packageName, + @NonNull ControllerCallbackLink caller, @NonNull String mediaId, + @Nullable Bundle extras) { + try { + mISessionController.prepareFromMediaId(packageName, caller, mediaId, extras); + } catch (RemoteException e) { + throw new RuntimeException(e); + } + } + + /** + * Tell system that a controller requests preparing media from given search query. + * + * @param packageName the package name of the controller + * @param caller the {@link ControllerCallbackLink} of the controller + * @param query the search query + * @param extras the extras included with this request. + */ + void prepareFromSearch(@NonNull String packageName, + @NonNull ControllerCallbackLink caller, @NonNull String query, + @Nullable Bundle extras) { + try { + mISessionController.prepareFromSearch(packageName, caller, query, extras); + } catch (RemoteException e) { + throw new RuntimeException(e); + } + } + + /** + * Tell system that a controller requests preparing media from given uri. + * + * @param packageName the package name of the controller + * @param caller the {@link ControllerCallbackLink} of the controller + * @param uri the uri of the media + * @param extras the extras included with this request. + */ + void prepareFromUri(@NonNull String packageName, @NonNull ControllerCallbackLink caller, + @NonNull Uri uri, @Nullable Bundle extras) { + try { + mISessionController.prepareFromUri(packageName, caller, uri, extras); + } catch (RemoteException e) { + throw new RuntimeException(e); + } + } + + /** + * Tell system that a controller requests playing media. + * + * @param packageName the package name of the controller + * @param caller the {@link ControllerCallbackLink} of the controller + */ + void play(@NonNull String packageName, @NonNull ControllerCallbackLink caller) { + try { + mISessionController.play(packageName, caller); + } catch (RemoteException e) { + throw new RuntimeException(e); + } + } + + /** + * Tell system that a controller requests playing media from given media ID. + * + * @param packageName the package name of the controller + * @param caller the {@link ControllerCallbackLink} of the controller + * @param mediaId the ID of the media + * @param extras the extras included with this request. + */ + void playFromMediaId(@NonNull String packageName, @NonNull ControllerCallbackLink caller, + @NonNull String mediaId, @Nullable Bundle extras) { + try { + mISessionController.playFromMediaId(packageName, caller, mediaId, extras); + } catch (RemoteException e) { + throw new RuntimeException(e); + } + } + + /** + * Tell system that a controller requests playing media from given search query. + * + * @param packageName the package name of the controller + * @param caller the {@link ControllerCallbackLink} of the controller + * @param query the search query + * @param extras the extras included with this request. + */ + void playFromSearch(@NonNull String packageName, @NonNull ControllerCallbackLink caller, + @NonNull String query, @Nullable Bundle extras) { + try { + mISessionController.playFromSearch(packageName, caller, query, extras); + } catch (RemoteException e) { + throw new RuntimeException(e); + } + } + + /** + * Tell system that a controller requests playing media from given uri. + * + * @param packageName the package name of the controller + * @param caller the {@link ControllerCallbackLink} of the controller + * @param uri the uri of the media + * @param extras the extras included with this request. + */ + void playFromUri(@NonNull String packageName, @NonNull ControllerCallbackLink caller, + @NonNull Uri uri, @Nullable Bundle extras) { + try { + mISessionController.playFromUri(packageName, caller, uri, extras); + } catch (RemoteException e) { + throw new RuntimeException(e); + } + } + + /** + * Tell system that a controller requests skipping to the queue item with given ID. + * + * @param packageName the package name of the controller + * @param caller the {@link ControllerCallbackLink} of the controller + * @param id the queue id of the item + */ + void skipToQueueItem(@NonNull String packageName, @NonNull ControllerCallbackLink caller, + long id) { + try { + mISessionController.skipToQueueItem(packageName, caller, id); + } catch (RemoteException e) { + throw new RuntimeException(e); + } + } + + /** + * Tell system that a controller requests pausing media. + * + * @param packageName the package name of the controller + * @param caller the {@link ControllerCallbackLink} of the controller + */ + void pause(@NonNull String packageName, @NonNull ControllerCallbackLink caller) { + try { + mISessionController.pause(packageName, caller); + } catch (RemoteException e) { + throw new RuntimeException(e); + } + } + + /** + * Tell system that a controller requests stopping media. + * + * @param packageName the package name of the controller + * @param caller the {@link ControllerCallbackLink} of the controller + */ + void stop(@NonNull String packageName, @NonNull ControllerCallbackLink caller) { + try { + mISessionController.stop(packageName, caller); + } catch (RemoteException e) { + throw new RuntimeException(e); + } + } + + /** + * Tell system that a controller requests skipping to the next queue item. + * + * @param packageName the package name of the controller + * @param caller the {@link ControllerCallbackLink} of the controller + */ + void next(@NonNull String packageName, @NonNull ControllerCallbackLink caller) { + try { + mISessionController.next(packageName, caller); + } catch (RemoteException e) { + throw new RuntimeException(e); + } + } + + /** + * Tell system that a controller requests skipping to the previous queue item. + * + * @param packageName the package name of the controller + * @param caller the {@link ControllerCallbackLink} of the controller + */ + void previous(@NonNull String packageName, @NonNull ControllerCallbackLink caller) { + try { + mISessionController.previous(packageName, caller); + } catch (RemoteException e) { + throw new RuntimeException(e); + } + } + + /** + * Tell system that a controller requests fast-forwarding. + * + * @param packageName the package name of the controller + * @param caller the {@link ControllerCallbackLink} of the controller + */ + void fastForward(@NonNull String packageName, @NonNull ControllerCallbackLink caller) { + try { + mISessionController.fastForward(packageName, caller); + } catch (RemoteException e) { + throw new RuntimeException(e); + } + } + + /** + * Tell system that a controller requests rewinding. + * + * @param packageName the package name of the controller + * @param caller the {@link ControllerCallbackLink} of the controller + */ + void rewind(@NonNull String packageName, @NonNull ControllerCallbackLink caller) { + try { + mISessionController.rewind(packageName, caller); + } catch (RemoteException e) { + throw new RuntimeException(e); + } + } + + /** + * Tell system that a controller requests seeking to the specific position. + * + * @param packageName the package name of the controller + * @param caller the {@link ControllerCallbackLink} of the controller + * @param pos the position to move to, in milliseconds + */ + void seekTo(@NonNull String packageName, @NonNull ControllerCallbackLink caller, + long pos) { + try { + mISessionController.seekTo(packageName, caller, pos); + } catch (RemoteException e) { + throw new RuntimeException(e); + } + } + + /** + * Tell system that a controller requests rating of the current media. + * + * @param packageName the package name of the controller + * @param caller the {@link ControllerCallbackLink} of the controller + * @param rating the rating of the current media + */ + void rate(@NonNull String packageName, @NonNull ControllerCallbackLink caller, + @NonNull Rating rating) { + try { + mISessionController.rate(packageName, caller, rating); + } catch (RemoteException e) { + throw new RuntimeException(e); + } + } + + /** + * Tell system that a controller sends a custom action. + * + * @param packageName the package name of the controller + * @param caller the {@link ControllerCallbackLink} of the controller + * @param action the name of the action + * @param args the arguments included with this action + */ + void sendCustomAction(@NonNull String packageName, + @NonNull ControllerCallbackLink caller, @NonNull String action, @Nullable Bundle args) { + try { + mISessionController.sendCustomAction(packageName, caller, action, args); + } catch (RemoteException e) { + throw new RuntimeException(e); + } + } + + /** + * Gets the current metadata of the connected session. + */ + @Nullable + public MediaMetadata getMetadata() { + try { + return mISessionController.getMetadata(); + } catch (RemoteException e) { + throw new RuntimeException(e); + } + } + + /** + * Gets the current playback state of the connected session. + */ + @Nullable + public PlaybackState getPlaybackState() { + try { + return mISessionController.getPlaybackState(); + } catch (RemoteException e) { + throw new RuntimeException(e); + } + } + + /** + * Gets the current queue of the connected session. + */ + @Nullable + public List<MediaSession.QueueItem> getQueue() { + try { + return mISessionController.getQueue(); + } catch (RemoteException e) { + throw new RuntimeException(e); + } + } + + /** + * Gets the current queue title of the connected session. + */ + @Nullable + public CharSequence getQueueTitle() { + try { + return mISessionController.getQueueTitle(); + } catch (RemoteException e) { + throw new RuntimeException(e); + } + } + + /** + * Gets the current extras of the connected session. + */ + @Nullable + public Bundle getExtras() { + try { + return mISessionController.getExtras(); + } catch (RemoteException e) { + throw new RuntimeException(e); + } + } + + /** + * Gets the current rating type of the connected session. + */ + public int getRatingType() { + try { + return mISessionController.getRatingType(); + } catch (RemoteException e) { + throw new RuntimeException(e); + } + } + + /** Gets the binder */ + @NonNull + public IBinder getBinder() { + return mISessionController.asBinder(); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeStrongBinder(mISessionController.asBinder()); + } + + /** + * Class for Stub implementation + */ + public abstract static class ControllerStub { + /** Stub method for ISessionController.sendCommand */ + public void sendCommand(@NonNull String packageName, @NonNull ControllerCallbackLink caller, + @NonNull String command, @Nullable Bundle args, @Nullable ResultReceiver cb) { + } + + /** Stub method for ISessionController.sendMediaButton */ + public boolean sendMediaButton(@NonNull String packageName, + @NonNull ControllerCallbackLink caller, boolean asSystemService, + @NonNull KeyEvent mediaButton) { + return false; + } + + /** Stub method for ISessionController.registerCallback */ + public void registerCallback(@NonNull String packageName, + @NonNull ControllerCallbackLink cb) { + } + + /** Stub method for ISessionController.unregisterCallback */ + public void unregisterCallback(@NonNull ControllerCallbackLink cb) { + } + + /** Stub method for ISessionController.getPackageName */ + @NonNull + public String getPackageName() { + return null; + } + + /** Stub method for ISessionController.getTag */ + @NonNull + public String getTag() { + return null; + } + + /** Stub method for ISessionController.getLaunchPendingIntent */ + @Nullable + public PendingIntent getLaunchPendingIntent() { + return null; + } + + /** Stub method for ISessionController.getFlags */ + public long getFlags() { + return 0; + } + + /** Stub method for ISessionController.getVolumeAttributes */ + @NonNull + public PlaybackInfo getVolumeAttributes() { + return null; + } + + /** Stub method for ISessionController.adjustVolume */ + public void adjustVolume(@NonNull String packageName, @NonNull String opPackageName, + @NonNull ControllerCallbackLink caller, boolean asSystemService, int direction, + int flags) { + } + + /** Stub method for ISessionController.setVolumeTo */ + public void setVolumeTo(@NonNull String packageName, @NonNull String opPackageName, + @NonNull ControllerCallbackLink caller, int value, int flags) { + } + + /** Stub method for ISessionController.prepare */ + public void prepare(@NonNull String packageName, @NonNull ControllerCallbackLink caller) { + } + + /** Stub method for ISessionController.prepareFromMediaId */ + public void prepareFromMediaId(@NonNull String packageName, + @NonNull ControllerCallbackLink caller, @NonNull String mediaId, + @Nullable Bundle extras) { + } + + /** Stub method for ISessionController.prepareFromSearch */ + public void prepareFromSearch(@NonNull String packageName, + @NonNull ControllerCallbackLink caller, @NonNull String query, + @Nullable Bundle extras) { + } + + /** Stub method for ISessionController.prepareFromUri */ + public void prepareFromUri(@NonNull String packageName, + @NonNull ControllerCallbackLink caller, @NonNull Uri uri, @Nullable Bundle extras) { + } + + /** Stub method for ISessionController.play */ + public void play(@NonNull String packageName, @NonNull ControllerCallbackLink caller) { + } + + /** Stub method for ISessionController.playFromMediaId */ + public void playFromMediaId(@NonNull String packageName, + @NonNull ControllerCallbackLink caller, @NonNull String mediaId, + @Nullable Bundle extras) { + } + + /** Stub method for ISessionController.playFromSearch */ + public void playFromSearch(@NonNull String packageName, + @NonNull ControllerCallbackLink caller, @NonNull String query, + @Nullable Bundle extras) { + } + + /** Stub method for ISessionController.playFromUri */ + public void playFromUri(@NonNull String packageName, @NonNull ControllerCallbackLink caller, + @NonNull Uri uri, @Nullable Bundle extras) { + } + + /** Stub method for ISessionController.skipToQueueItem */ + public void skipToQueueItem(@NonNull String packageName, + @NonNull ControllerCallbackLink caller, long id) { + } + + /** Stub method for ISessionController.pause */ + public void pause(@NonNull String packageName, @NonNull ControllerCallbackLink caller) { + } + + /** Stub method for ISessionController.stop */ + public void stop(@NonNull String packageName, @NonNull ControllerCallbackLink caller) { + } + + /** Stub method for ISessionController.next */ + public void next(@NonNull String packageName, @NonNull ControllerCallbackLink caller) { + } + + /** Stub method for ISessionController.previous */ + public void previous(@NonNull String packageName, @NonNull ControllerCallbackLink caller) { + } + + /** Stub method for ISessionController.fastForward */ + public void fastForward(@NonNull String packageName, + @NonNull ControllerCallbackLink caller) { + } + + /** Stub method for ISessionController.rewind */ + public void rewind(@NonNull String packageName, @NonNull ControllerCallbackLink caller) { + } + + /** Stub method for ISessionController.seekTo */ + public void seekTo(@NonNull String packageName, @NonNull ControllerCallbackLink caller, + long pos) { + } + + /** Stub method for ISessionController.rate */ + public void rate(@NonNull String packageName, @NonNull ControllerCallbackLink caller, + @NonNull Rating rating) { + } + + /** Stub method for ISessionController.sendCustomAction */ + public void sendCustomAction(@NonNull String packageName, + @NonNull ControllerCallbackLink caller, @NonNull String action, + @Nullable Bundle args) { + } + + /** Stub method for ISessionController.getMetadata */ + @Nullable + public MediaMetadata getMetadata() { + return null; + } + + /** Stub method for ISessionController.getPlaybackState */ + @Nullable + public PlaybackState getPlaybackState() { + return null; + } + + /** Stub method for ISessionController.getQueue */ + @Nullable + public List<MediaSession.QueueItem> getQueue() { + return null; + } + + /** Stub method for ISessionController.getQueueTitle */ + @Nullable + public CharSequence getQueueTitle() { + return null; + } + + /** Stub method for ISessionController.getExtras */ + @Nullable + public Bundle getExtras() { + return null; + } + + /** Stub method for ISessionController.getRatingType */ + public int getRatingType() { + return Rating.RATING_NONE; + } + } + + private class StubProxy extends ISessionController.Stub { + @Override + public void sendCommand(String packageName, ControllerCallbackLink caller, + String command, Bundle args, ResultReceiver cb) { + mControllerStub.sendCommand(packageName, caller, command, args, cb); + } + + @Override + public boolean sendMediaButton(String packageName, ControllerCallbackLink caller, + boolean asSystemService, KeyEvent mediaButton) { + return mControllerStub.sendMediaButton(packageName, caller, asSystemService, + mediaButton); + } + + @Override + public void registerCallback(String packageName, ControllerCallbackLink cb) { + mControllerStub.registerCallback(packageName, cb); + } + + @Override + public void unregisterCallback(ControllerCallbackLink cb) { + mControllerStub.unregisterCallback(cb); + } + + @Override + public String getPackageName() { + return mControllerStub.getPackageName(); + } + + @Override + public String getTag() { + return mControllerStub.getTag(); + } + + @Override + public PendingIntent getLaunchPendingIntent() { + return mControllerStub.getLaunchPendingIntent(); + } + + @Override + public long getFlags() { + return mControllerStub.getFlags(); + } + + @Override + public PlaybackInfo getVolumeAttributes() { + return mControllerStub.getVolumeAttributes(); + } + + @Override + public void adjustVolume(String packageName, String opPackageName, + ControllerCallbackLink caller, boolean asSystemService, int direction, + int flags) { + mControllerStub.adjustVolume(packageName, opPackageName, caller, asSystemService, + direction, flags); + } + + @Override + public void setVolumeTo(String packageName, String opPackageName, + ControllerCallbackLink caller, int value, int flags) { + mControllerStub.setVolumeTo(packageName, opPackageName, caller, value, flags); + } + + @Override + public void prepare(String packageName, ControllerCallbackLink caller) { + mControllerStub.prepare(packageName, caller); + } + + @Override + public void prepareFromMediaId(String packageName, ControllerCallbackLink caller, + String mediaId, Bundle extras) { + mControllerStub.prepareFromMediaId(packageName, caller, mediaId, extras); + } + + @Override + public void prepareFromSearch(String packageName, ControllerCallbackLink caller, + String query, Bundle extras) { + mControllerStub.prepareFromSearch(packageName, caller, query, extras); + } + + @Override + public void prepareFromUri(String packageName, ControllerCallbackLink caller, + Uri uri, Bundle extras) { + mControllerStub.prepareFromUri(packageName, caller, uri, extras); + } + + @Override + public void play(String packageName, ControllerCallbackLink caller) { + mControllerStub.play(packageName, caller); + } + + @Override + public void playFromMediaId(String packageName, ControllerCallbackLink caller, + String mediaId, Bundle extras) { + mControllerStub.playFromMediaId(packageName, caller, mediaId, extras); + } + + @Override + public void playFromSearch(String packageName, ControllerCallbackLink caller, + String query, Bundle extras) { + mControllerStub.playFromSearch(packageName, caller, query, extras); + } + + @Override + public void playFromUri(String packageName, ControllerCallbackLink caller, + Uri uri, Bundle extras) { + mControllerStub.playFromUri(packageName, caller, uri, extras); + } + + @Override + public void skipToQueueItem(String packageName, ControllerCallbackLink caller, long id) { + mControllerStub.skipToQueueItem(packageName, caller, id); + } + + @Override + public void pause(String packageName, ControllerCallbackLink caller) { + mControllerStub.pause(packageName, caller); + } + + @Override + public void stop(String packageName, ControllerCallbackLink caller) { + mControllerStub.stop(packageName, caller); + } + + @Override + public void next(String packageName, ControllerCallbackLink caller) { + mControllerStub.next(packageName, caller); + } + + @Override + public void previous(String packageName, ControllerCallbackLink caller) { + mControllerStub.previous(packageName, caller); + } + + @Override + public void fastForward(String packageName, ControllerCallbackLink caller) { + mControllerStub.fastForward(packageName, caller); + } + + @Override + public void rewind(String packageName, ControllerCallbackLink caller) { + mControllerStub.rewind(packageName, caller); + } + + @Override + public void seekTo(String packageName, ControllerCallbackLink caller, long pos) { + mControllerStub.seekTo(packageName, caller, pos); + } + + @Override + public void rate(String packageName, ControllerCallbackLink caller, Rating rating) { + mControllerStub.rate(packageName, caller, rating); + } + + @Override + public void sendCustomAction(String packageName, ControllerCallbackLink caller, + String action, Bundle args) { + mControllerStub.sendCustomAction(packageName, caller, action, args); + } + + @Override + public MediaMetadata getMetadata() { + return mControllerStub.getMetadata(); + } + + @Override + public PlaybackState getPlaybackState() { + return mControllerStub.getPlaybackState(); + } + + @Override + public List<MediaSession.QueueItem> getQueue() { + return mControllerStub.getQueue(); + } + + @Override + public CharSequence getQueueTitle() { + return mControllerStub.getQueueTitle(); + } + + @Override + public Bundle getExtras() { + return mControllerStub.getExtras(); + } + + @Override + public int getRatingType() { + return mControllerStub.getRatingType(); + } + } +} diff --git a/media/java/android/media/session/ISession.aidl b/media/java/android/media/session/ISession.aidl index 1524ad9c5de1..9b4e2bca2ea4 100644 --- a/media/java/android/media/session/ISession.aidl +++ b/media/java/android/media/session/ISession.aidl @@ -18,7 +18,7 @@ package android.media.session; import android.app.PendingIntent; import android.media.AudioAttributes; import android.media.MediaMetadata; -import android.media.session.ISessionController; +import android.media.session.ControllerLink; import android.media.session.PlaybackState; import android.media.session.MediaSession; import android.os.Bundle; @@ -30,12 +30,12 @@ import android.os.ResultReceiver; */ interface ISession { void sendEvent(String event, in Bundle data); - ISessionController getController(); + ControllerLink getController(); void setFlags(int flags); void setActive(boolean active); void setMediaButtonReceiver(in PendingIntent mbr); void setLaunchPendingIntent(in PendingIntent pi); - void destroy(); + void destroySession(); // These commands are for the TransportPerformer void setMetadata(in MediaMetadata metadata, long duration, String metadataDescription); diff --git a/media/java/android/media/session/ISessionController.aidl b/media/java/android/media/session/ISessionController.aidl index 2ba09fd92af5..787cb7770514 100644 --- a/media/java/android/media/session/ISessionController.aidl +++ b/media/java/android/media/session/ISessionController.aidl @@ -39,9 +39,8 @@ interface ISessionController { String command, in Bundle args, in ResultReceiver cb); boolean sendMediaButton(String packageName, in ControllerCallbackLink caller, boolean asSystemService, in KeyEvent mediaButton); - void registerCallbackListener(String packageName, in ControllerCallbackLink cb); - void unregisterCallbackListener(in ControllerCallbackLink cb); - boolean isTransportControlEnabled(); + void registerCallback(String packageName, in ControllerCallbackLink cb); + void unregisterCallback(in ControllerCallbackLink cb); String getPackageName(); String getTag(); PendingIntent getLaunchPendingIntent(); diff --git a/media/java/android/media/session/ISessionManager.aidl b/media/java/android/media/session/ISessionManager.aidl index 46516e0f493b..ed162504c553 100644 --- a/media/java/android/media/session/ISessionManager.aidl +++ b/media/java/android/media/session/ISessionManager.aidl @@ -18,13 +18,14 @@ package android.media.session; import android.content.ComponentName; import android.media.IRemoteVolumeController; import android.media.Session2Token; +import android.media.session.ControllerLink; import android.media.session.IActiveSessionsListener; import android.media.session.ICallback; import android.media.session.IOnMediaKeyListener; import android.media.session.IOnVolumeKeyLongPressListener; -import android.media.session.ISession; import android.media.session.ISession2TokensListener; import android.media.session.SessionCallbackLink; +import android.media.session.SessionLink; import android.os.Bundle; import android.view.KeyEvent; @@ -33,9 +34,10 @@ import android.view.KeyEvent; * @hide */ interface ISessionManager { - ISession createSession(String packageName, in SessionCallbackLink cb, String tag, int userId); + SessionLink createSession(String packageName, in SessionCallbackLink sessionCb, String tag, + int userId); void notifySession2Created(in Session2Token sessionToken); - List<IBinder> getSessions(in ComponentName compName, int userId); + List<ControllerLink> getSessions(in ComponentName compName, int userId); List<Session2Token> getSession2Tokens(int userId); void dispatchMediaKeyEvent(String packageName, boolean asSystemService, in KeyEvent keyEvent, boolean needWakeLock); diff --git a/media/java/android/media/session/MediaController.java b/media/java/android/media/session/MediaController.java index a1b8170cf4c3..9d537c8c2fcb 100644 --- a/media/java/android/media/session/MediaController.java +++ b/media/java/android/media/session/MediaController.java @@ -34,7 +34,6 @@ import android.os.Looper; import android.os.Message; import android.os.Parcel; import android.os.Parcelable; -import android.os.RemoteException; import android.os.ResultReceiver; import android.text.TextUtils; import android.util.Log; @@ -68,12 +67,11 @@ public final class MediaController { private static final int MSG_UPDATE_EXTRAS = 7; private static final int MSG_DESTROYED = 8; - private final ISessionController mSessionBinder; + private final ControllerLink mSessionBinder; private final MediaSession.Token mToken; private final Context mContext; - private final ControllerCallbackLink mCbStub = - new ControllerCallbackLink(new CallbackStub(this)); + private final ControllerCallbackLink mCbStub; private final ArrayList<MessageHandler> mCallbacks = new ArrayList<MessageHandler>(); private final Object mLock = new Object(); @@ -84,12 +82,11 @@ public final class MediaController { private final TransportControls mTransportControls; /** - * Call for creating a MediaController directly from a binder. Should only + * Call for creating a MediaController directly from a controller link. Should only * be used by framework code. - * * @hide */ - public MediaController(Context context, ISessionController sessionBinder) { + public MediaController(Context context, ControllerLink sessionBinder) { if (sessionBinder == null) { throw new IllegalArgumentException("Session token cannot be null"); } @@ -100,6 +97,17 @@ public final class MediaController { mTransportControls = new TransportControls(); mToken = new MediaSession.Token(sessionBinder); mContext = context; + mCbStub = new ControllerCallbackLink(context, new CallbackStub(this)); + } + + /** + * Call for creating a MediaController directly from a binder. Should only + * be used by framework code. + * @hide + * TODO: remove this constructor + */ + public MediaController(Context context, ISessionController sessionBinder) { + this(context, new ControllerLink(sessionBinder.asBinder())); } /** @@ -158,7 +166,7 @@ public final class MediaController { try { return mSessionBinder.sendMediaButton(mContext.getPackageName(), mCbStub, asSystemService, keyEvent); - } catch (RemoteException e) { + } catch (RuntimeException e) { // System is dead. =( } return false; @@ -195,7 +203,7 @@ public final class MediaController { mSessionBinder.adjustVolume(mContext.getPackageName(), mContext.getOpPackageName(), mCbStub, true, direction, AudioManager.FLAG_SHOW_UI); - } catch (RemoteException e) { + } catch (RuntimeException e) { Log.wtf(TAG, "Error calling adjustVolumeBy", e); } } @@ -209,7 +217,7 @@ public final class MediaController { // AppOpsManager usages. mSessionBinder.adjustVolume(mContext.getPackageName(), mContext.getOpPackageName(), mCbStub, true, 0, flags); - } catch (RemoteException e) { + } catch (RuntimeException e) { Log.wtf(TAG, "Error calling adjustVolumeBy", e); } } @@ -224,7 +232,7 @@ public final class MediaController { public @Nullable PlaybackState getPlaybackState() { try { return mSessionBinder.getPlaybackState(); - } catch (RemoteException e) { + } catch (RuntimeException e) { Log.wtf(TAG, "Error calling getPlaybackState.", e); return null; } @@ -238,7 +246,7 @@ public final class MediaController { public @Nullable MediaMetadata getMetadata() { try { return mSessionBinder.getMetadata(); - } catch (RemoteException e) { + } catch (RuntimeException e) { Log.wtf(TAG, "Error calling getMetadata.", e); return null; } @@ -253,7 +261,7 @@ public final class MediaController { public @Nullable List<MediaSession.QueueItem> getQueue() { try { return mSessionBinder.getQueue(); - } catch (RemoteException e) { + } catch (RuntimeException e) { Log.wtf(TAG, "Error calling getQueue.", e); } return null; @@ -265,7 +273,7 @@ public final class MediaController { public @Nullable CharSequence getQueueTitle() { try { return mSessionBinder.getQueueTitle(); - } catch (RemoteException e) { + } catch (RuntimeException e) { Log.wtf(TAG, "Error calling getQueueTitle", e); } return null; @@ -277,7 +285,7 @@ public final class MediaController { public @Nullable Bundle getExtras() { try { return mSessionBinder.getExtras(); - } catch (RemoteException e) { + } catch (RuntimeException e) { Log.wtf(TAG, "Error calling getExtras", e); } return null; @@ -300,7 +308,7 @@ public final class MediaController { public int getRatingType() { try { return mSessionBinder.getRatingType(); - } catch (RemoteException e) { + } catch (RuntimeException e) { Log.wtf(TAG, "Error calling getRatingType.", e); return Rating.RATING_NONE; } @@ -314,7 +322,7 @@ public final class MediaController { public @MediaSession.SessionFlags long getFlags() { try { return mSessionBinder.getFlags(); - } catch (RemoteException e) { + } catch (RuntimeException e) { Log.wtf(TAG, "Error calling getFlags.", e); } return 0; @@ -328,7 +336,7 @@ public final class MediaController { public @Nullable PlaybackInfo getPlaybackInfo() { try { return mSessionBinder.getVolumeAttributes(); - } catch (RemoteException e) { + } catch (RuntimeException e) { Log.wtf(TAG, "Error calling getAudioInfo.", e); } return null; @@ -343,7 +351,7 @@ public final class MediaController { public @Nullable PendingIntent getSessionActivity() { try { return mSessionBinder.getLaunchPendingIntent(); - } catch (RemoteException e) { + } catch (RuntimeException e) { Log.wtf(TAG, "Error calling getPendingIntent.", e); } return null; @@ -376,7 +384,7 @@ public final class MediaController { // AppOpsManager usages. mSessionBinder.setVolumeTo(mContext.getPackageName(), mContext.getOpPackageName(), mCbStub, value, flags); - } catch (RemoteException e) { + } catch (RuntimeException e) { Log.wtf(TAG, "Error calling setVolumeTo.", e); } } @@ -401,7 +409,7 @@ public final class MediaController { // AppOpsManager usages. mSessionBinder.adjustVolume(mContext.getPackageName(), mContext.getOpPackageName(), mCbStub, false, direction, flags); - } catch (RemoteException e) { + } catch (RuntimeException e) { Log.wtf(TAG, "Error calling adjustVolumeBy.", e); } } @@ -467,7 +475,7 @@ public final class MediaController { } try { mSessionBinder.sendCommand(mContext.getPackageName(), mCbStub, command, args, cb); - } catch (RemoteException e) { + } catch (RuntimeException e) { Log.d(TAG, "Dead object in sendCommand.", e); } } @@ -481,7 +489,7 @@ public final class MediaController { if (mPackageName == null) { try { mPackageName = mSessionBinder.getPackageName(); - } catch (RemoteException e) { + } catch (RuntimeException e) { Log.d(TAG, "Dead object in getPackageName.", e); } } @@ -498,7 +506,7 @@ public final class MediaController { if (mTag == null) { try { mTag = mSessionBinder.getTag(); - } catch (RemoteException e) { + } catch (RuntimeException e) { Log.d(TAG, "Dead object in getTag.", e); } } @@ -508,7 +516,7 @@ public final class MediaController { /* * @hide */ - ISessionController getSessionBinder() { + ControllerLink getSessionBinder() { return mSessionBinder; } @@ -518,7 +526,7 @@ public final class MediaController { @UnsupportedAppUsage public boolean controlsSameSession(MediaController other) { if (other == null) return false; - return mSessionBinder.asBinder() == other.getSessionBinder().asBinder(); + return mSessionBinder.getBinder() == other.getSessionBinder().getBinder(); } private void addCallbackLocked(Callback cb, Handler handler) { @@ -532,9 +540,9 @@ public final class MediaController { if (!mCbRegistered) { try { - mSessionBinder.registerCallbackListener(mContext.getPackageName(), mCbStub); + mSessionBinder.registerCallback(mContext.getPackageName(), mCbStub); mCbRegistered = true; - } catch (RemoteException e) { + } catch (RuntimeException e) { Log.e(TAG, "Dead object in registerCallback", e); } } @@ -552,8 +560,8 @@ public final class MediaController { } if (mCbRegistered && mCallbacks.size() == 0) { try { - mSessionBinder.unregisterCallbackListener(mCbStub); - } catch (RemoteException e) { + mSessionBinder.unregisterCallback(mCbStub); + } catch (RuntimeException e) { Log.e(TAG, "Dead object in removeCallbackLocked"); } mCbRegistered = false; @@ -680,7 +688,7 @@ public final class MediaController { public void prepare() { try { mSessionBinder.prepare(mContext.getPackageName(), mCbStub); - } catch (RemoteException e) { + } catch (RuntimeException e) { Log.wtf(TAG, "Error calling prepare.", e); } } @@ -705,7 +713,7 @@ public final class MediaController { try { mSessionBinder.prepareFromMediaId(mContext.getPackageName(), mCbStub, mediaId, extras); - } catch (RemoteException e) { + } catch (RuntimeException e) { Log.wtf(TAG, "Error calling prepare(" + mediaId + ").", e); } } @@ -732,7 +740,7 @@ public final class MediaController { try { mSessionBinder.prepareFromSearch(mContext.getPackageName(), mCbStub, query, extras); - } catch (RemoteException e) { + } catch (RuntimeException e) { Log.wtf(TAG, "Error calling prepare(" + query + ").", e); } } @@ -756,7 +764,7 @@ public final class MediaController { } try { mSessionBinder.prepareFromUri(mContext.getPackageName(), mCbStub, uri, extras); - } catch (RemoteException e) { + } catch (RuntimeException e) { Log.wtf(TAG, "Error calling prepare(" + uri + ").", e); } } @@ -767,7 +775,7 @@ public final class MediaController { public void play() { try { mSessionBinder.play(mContext.getPackageName(), mCbStub); - } catch (RemoteException e) { + } catch (RuntimeException e) { Log.wtf(TAG, "Error calling play.", e); } } @@ -787,7 +795,7 @@ public final class MediaController { try { mSessionBinder.playFromMediaId(mContext.getPackageName(), mCbStub, mediaId, extras); - } catch (RemoteException e) { + } catch (RuntimeException e) { Log.wtf(TAG, "Error calling play(" + mediaId + ").", e); } } @@ -809,7 +817,7 @@ public final class MediaController { } try { mSessionBinder.playFromSearch(mContext.getPackageName(), mCbStub, query, extras); - } catch (RemoteException e) { + } catch (RuntimeException e) { Log.wtf(TAG, "Error calling play(" + query + ").", e); } } @@ -828,7 +836,7 @@ public final class MediaController { } try { mSessionBinder.playFromUri(mContext.getPackageName(), mCbStub, uri, extras); - } catch (RemoteException e) { + } catch (RuntimeException e) { Log.wtf(TAG, "Error calling play(" + uri + ").", e); } } @@ -840,7 +848,7 @@ public final class MediaController { public void skipToQueueItem(long id) { try { mSessionBinder.skipToQueueItem(mContext.getPackageName(), mCbStub, id); - } catch (RemoteException e) { + } catch (RuntimeException e) { Log.wtf(TAG, "Error calling skipToItem(" + id + ").", e); } } @@ -852,7 +860,7 @@ public final class MediaController { public void pause() { try { mSessionBinder.pause(mContext.getPackageName(), mCbStub); - } catch (RemoteException e) { + } catch (RuntimeException e) { Log.wtf(TAG, "Error calling pause.", e); } } @@ -864,7 +872,7 @@ public final class MediaController { public void stop() { try { mSessionBinder.stop(mContext.getPackageName(), mCbStub); - } catch (RemoteException e) { + } catch (RuntimeException e) { Log.wtf(TAG, "Error calling stop.", e); } } @@ -877,7 +885,7 @@ public final class MediaController { public void seekTo(long pos) { try { mSessionBinder.seekTo(mContext.getPackageName(), mCbStub, pos); - } catch (RemoteException e) { + } catch (RuntimeException e) { Log.wtf(TAG, "Error calling seekTo.", e); } } @@ -889,7 +897,7 @@ public final class MediaController { public void fastForward() { try { mSessionBinder.fastForward(mContext.getPackageName(), mCbStub); - } catch (RemoteException e) { + } catch (RuntimeException e) { Log.wtf(TAG, "Error calling fastForward.", e); } } @@ -900,7 +908,7 @@ public final class MediaController { public void skipToNext() { try { mSessionBinder.next(mContext.getPackageName(), mCbStub); - } catch (RemoteException e) { + } catch (RuntimeException e) { Log.wtf(TAG, "Error calling next.", e); } } @@ -912,7 +920,7 @@ public final class MediaController { public void rewind() { try { mSessionBinder.rewind(mContext.getPackageName(), mCbStub); - } catch (RemoteException e) { + } catch (RuntimeException e) { Log.wtf(TAG, "Error calling rewind.", e); } } @@ -923,7 +931,7 @@ public final class MediaController { public void skipToPrevious() { try { mSessionBinder.previous(mContext.getPackageName(), mCbStub); - } catch (RemoteException e) { + } catch (RuntimeException e) { Log.wtf(TAG, "Error calling previous.", e); } } @@ -938,7 +946,7 @@ public final class MediaController { public void setRating(Rating rating) { try { mSessionBinder.rate(mContext.getPackageName(), mCbStub, rating); - } catch (RemoteException e) { + } catch (RuntimeException e) { Log.wtf(TAG, "Error calling rate.", e); } } @@ -973,7 +981,7 @@ public final class MediaController { } try { mSessionBinder.sendCustomAction(mContext.getPackageName(), mCbStub, action, args); - } catch (RemoteException e) { + } catch (RuntimeException e) { Log.d(TAG, "Dead object in sendCustomAction.", e); } } diff --git a/media/java/android/media/session/MediaSession.java b/media/java/android/media/session/MediaSession.java index e07cf15d11c9..881e6ee6a907 100644 --- a/media/java/android/media/session/MediaSession.java +++ b/media/java/android/media/session/MediaSession.java @@ -37,9 +37,7 @@ import android.os.Looper; import android.os.Message; import android.os.Parcel; import android.os.Parcelable; -import android.os.RemoteException; import android.os.ResultReceiver; -import android.os.UserHandle; import android.service.media.MediaBrowserService; import android.text.TextUtils; import android.util.Log; @@ -128,7 +126,7 @@ public final class MediaSession { private final MediaSession.Token mSessionToken; private final MediaController mController; - private final ISession mBinder; + private final SessionLink mSessionLink; private final SessionCallbackLink mCbStub; // Do not change the name of mCallback. Support lib accesses this by using reflection. @@ -149,21 +147,6 @@ public final class MediaSession { * @param tag A short name for debugging purposes. */ public MediaSession(@NonNull Context context, @NonNull String tag) { - this(context, tag, UserHandle.myUserId()); - } - - /** - * Creates a new session as the specified user. To create a session as a - * user other than your own you must hold the - * {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL} - * permission. - * - * @param context The context to use to create the session. - * @param tag A short name for debugging purposes. - * @param userId The user id to create the session as. - * @hide - */ - public MediaSession(@NonNull Context context, @NonNull String tag, int userId) { if (context == null) { throw new IllegalArgumentException("context cannot be null."); } @@ -172,14 +155,14 @@ public final class MediaSession { } mMaxBitmapSize = context.getResources().getDimensionPixelSize( com.android.internal.R.dimen.config_mediaMetadataBitmapMaxSize); - mCbStub = new SessionCallbackLink(new CallbackStub(this)); + mCbStub = new SessionCallbackLink(context, new CallbackStub(this)); MediaSessionManager manager = (MediaSessionManager) context .getSystemService(Context.MEDIA_SESSION_SERVICE); try { - mBinder = manager.createSession(mCbStub, tag, userId); - mSessionToken = new Token(mBinder.getController()); + mSessionLink = manager.createSession(mCbStub, tag); + mSessionToken = new Token(mSessionLink.getController()); mController = new MediaController(context, mSessionToken); - } catch (RemoteException e) { + } catch (RuntimeException e) { throw new RuntimeException("Remote error creating session.", e); } } @@ -236,8 +219,8 @@ public final class MediaSession { */ public void setSessionActivity(@Nullable PendingIntent pi) { try { - mBinder.setLaunchPendingIntent(pi); - } catch (RemoteException e) { + mSessionLink.setLaunchPendingIntent(pi); + } catch (RuntimeException e) { Log.wtf(TAG, "Failure in setLaunchPendingIntent.", e); } } @@ -252,8 +235,8 @@ public final class MediaSession { */ public void setMediaButtonReceiver(@Nullable PendingIntent mbr) { try { - mBinder.setMediaButtonReceiver(mbr); - } catch (RemoteException e) { + mSessionLink.setMediaButtonReceiver(mbr); + } catch (RuntimeException e) { Log.wtf(TAG, "Failure in setMediaButtonReceiver.", e); } } @@ -265,8 +248,8 @@ public final class MediaSession { */ public void setFlags(@SessionFlags int flags) { try { - mBinder.setFlags(flags); - } catch (RemoteException e) { + mSessionLink.setFlags(flags); + } catch (RuntimeException e) { Log.wtf(TAG, "Failure in setFlags.", e); } } @@ -287,8 +270,8 @@ public final class MediaSession { throw new IllegalArgumentException("Attributes cannot be null for local playback."); } try { - mBinder.setPlaybackToLocal(attributes); - } catch (RemoteException e) { + mSessionLink.setPlaybackToLocal(attributes); + } catch (RuntimeException e) { Log.wtf(TAG, "Failure in setPlaybackToLocal.", e); } } @@ -319,10 +302,10 @@ public final class MediaSession { }); try { - mBinder.setPlaybackToRemote(volumeProvider.getVolumeControl(), + mSessionLink.setPlaybackToRemote(volumeProvider.getVolumeControl(), volumeProvider.getMaxVolume()); - mBinder.setCurrentVolume(volumeProvider.getCurrentVolume()); - } catch (RemoteException e) { + mSessionLink.setCurrentVolume(volumeProvider.getCurrentVolume()); + } catch (RuntimeException e) { Log.wtf(TAG, "Failure in setPlaybackToRemote.", e); } } @@ -340,9 +323,9 @@ public final class MediaSession { return; } try { - mBinder.setActive(active); + mSessionLink.setActive(active); mActive = active; - } catch (RemoteException e) { + } catch (RuntimeException e) { Log.wtf(TAG, "Failure in setActive.", e); } } @@ -369,8 +352,8 @@ public final class MediaSession { throw new IllegalArgumentException("event cannot be null or empty"); } try { - mBinder.sendEvent(event, extras); - } catch (RemoteException e) { + mSessionLink.sendEvent(event, extras); + } catch (RuntimeException e) { Log.wtf(TAG, "Error sending event", e); } } @@ -382,8 +365,8 @@ public final class MediaSession { */ public void release() { try { - mBinder.destroy(); - } catch (RemoteException e) { + mSessionLink.destroySession(); + } catch (RuntimeException e) { Log.wtf(TAG, "Error releasing session: ", e); } } @@ -418,8 +401,8 @@ public final class MediaSession { public void setPlaybackState(@Nullable PlaybackState state) { mPlaybackState = state; try { - mBinder.setPlaybackState(state); - } catch (RemoteException e) { + mSessionLink.setPlaybackState(state); + } catch (RuntimeException e) { Log.wtf(TAG, "Dead object in setPlaybackState.", e); } } @@ -447,8 +430,8 @@ public final class MediaSession { String metadataDescription = "size=" + fields + ", description=" + description; try { - mBinder.setMetadata(metadata, duration, metadataDescription); - } catch (RemoteException e) { + mSessionLink.setMetadata(metadata, duration, metadataDescription); + } catch (RuntimeException e) { Log.wtf(TAG, "Dead object in setPlaybackState.", e); } } @@ -466,8 +449,8 @@ public final class MediaSession { */ public void setQueue(@Nullable List<QueueItem> queue) { try { - mBinder.setQueue(queue); - } catch (RemoteException e) { + mSessionLink.setQueue(queue); + } catch (RuntimeException e) { Log.wtf("Dead object in setQueue.", e); } } @@ -481,8 +464,8 @@ public final class MediaSession { */ public void setQueueTitle(@Nullable CharSequence title) { try { - mBinder.setQueueTitle(title); - } catch (RemoteException e) { + mSessionLink.setQueueTitle(title); + } catch (RuntimeException e) { Log.wtf("Dead object in setQueueTitle.", e); } } @@ -502,8 +485,8 @@ public final class MediaSession { */ public void setRatingType(@Rating.Style int type) { try { - mBinder.setRatingType(type); - } catch (RemoteException e) { + mSessionLink.setRatingType(type); + } catch (RuntimeException e) { Log.e(TAG, "Error in setRatingType.", e); } } @@ -517,8 +500,8 @@ public final class MediaSession { */ public void setExtras(@Nullable Bundle extras) { try { - mBinder.setExtras(extras); - } catch (RemoteException e) { + mSessionLink.setExtras(extras); + } catch (RuntimeException e) { Log.wtf("Dead object in setExtras.", e); } } @@ -553,8 +536,8 @@ public final class MediaSession { } } try { - mBinder.setCurrentVolume(provider.getCurrentVolume()); - } catch (RemoteException e) { + mSessionLink.setCurrentVolume(provider.getCurrentVolume()); + } catch (RuntimeException e) { Log.e(TAG, "Error in notifyVolumeChanged", e); } } @@ -709,12 +692,12 @@ public final class MediaSession { */ public static final class Token implements Parcelable { - private ISessionController mBinder; + private ControllerLink mBinder; /** * @hide */ - public Token(ISessionController binder) { + public Token(ControllerLink binder) { mBinder = binder; } @@ -725,14 +708,14 @@ public final class MediaSession { @Override public void writeToParcel(Parcel dest, int flags) { - dest.writeStrongBinder(mBinder.asBinder()); + dest.writeParcelable(mBinder, flags); } @Override public int hashCode() { final int prime = 31; int result = 1; - result = prime * result + ((mBinder == null) ? 0 : mBinder.asBinder().hashCode()); + result = prime * result + ((mBinder == null) ? 0 : mBinder.getBinder().hashCode()); return result; } @@ -748,20 +731,22 @@ public final class MediaSession { if (mBinder == null) { if (other.mBinder != null) return false; - } else if (!mBinder.asBinder().equals(other.mBinder.asBinder())) + } else if (!mBinder.getBinder().equals(other.mBinder.getBinder())) { return false; + } return true; } - ISessionController getBinder() { + ControllerLink getBinder() { return mBinder; } - public static final Parcelable.Creator<Token> CREATOR - = new Parcelable.Creator<Token>() { + public static final Parcelable.Creator<Token> CREATOR = + new Parcelable.Creator<Token>() { @Override public Token createFromParcel(Parcel in) { - return new Token(ISessionController.Stub.asInterface(in.readStrongBinder())); + ControllerLink link = in.readParcelable(null); + return new Token(link); } @Override diff --git a/media/java/android/media/session/MediaSessionManager.java b/media/java/android/media/session/MediaSessionManager.java index 4596c22985c9..77e758fcf2dd 100644 --- a/media/java/android/media/session/MediaSessionManager.java +++ b/media/java/android/media/session/MediaSessionManager.java @@ -104,9 +104,14 @@ public final class MediaSessionManager { * @return The binder object from the system * @hide */ - public @NonNull ISession createSession(@NonNull SessionCallbackLink cbStub, - @NonNull String tag, int userId) throws RemoteException { - return mService.createSession(mContext.getPackageName(), cbStub, tag, userId); + @NonNull + public SessionLink createSession(@NonNull SessionCallbackLink cbStub, @NonNull String tag) { + try { + return mService.createSession(mContext.getPackageName(), cbStub, tag, + UserHandle.myUserId()); + } catch (RemoteException e) { + throw new RuntimeException(e); + } } /** @@ -171,11 +176,10 @@ public final class MediaSessionManager { @Nullable ComponentName notificationListener, int userId) { ArrayList<MediaController> controllers = new ArrayList<MediaController>(); try { - List<IBinder> binders = mService.getSessions(notificationListener, userId); + List<ControllerLink> binders = mService.getSessions(notificationListener, userId); int size = binders.size(); for (int i = 0; i < size; i++) { - MediaController controller = new MediaController(mContext, ISessionController.Stub - .asInterface(binders.get(i))); + MediaController controller = new MediaController(mContext, binders.get(i)); controllers.add(controller); } } catch (RemoteException e) { diff --git a/media/java/android/media/session/SessionCallbackLink.java b/media/java/android/media/session/SessionCallbackLink.java index 7547bffa3b18..0265687bcd54 100644 --- a/media/java/android/media/session/SessionCallbackLink.java +++ b/media/java/android/media/session/SessionCallbackLink.java @@ -16,31 +16,40 @@ package android.media.session; +import android.Manifest; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.RequiresPermission; +import android.annotation.SystemApi; +import android.content.Context; import android.content.Intent; +import android.content.pm.PackageManager; import android.media.Rating; import android.net.Uri; +import android.os.Binder; import android.os.Bundle; import android.os.IBinder; import android.os.Parcel; import android.os.Parcelable; +import android.os.Process; import android.os.RemoteException; import android.os.ResultReceiver; /** * Handles incoming commands to {@link MediaSession.Callback}. - * <p> - * This API is not generally intended for third party application developers. + * @hide */ +@SystemApi public final class SessionCallbackLink implements Parcelable { + final Context mContext; final CallbackStub mCallbackStub; final ISessionCallback mISessionCallback; /** * Constructor for stub (Callee) */ - SessionCallbackLink(@NonNull CallbackStub callbackStub) { + SessionCallbackLink(@NonNull Context context, @NonNull CallbackStub callbackStub) { + mContext = context; mCallbackStub = callbackStub; mISessionCallback = new CallbackStubProxy(); } @@ -48,9 +57,10 @@ public final class SessionCallbackLink implements Parcelable { /** * Constructor for interface (Caller) */ - SessionCallbackLink(Parcel in) { + public SessionCallbackLink(IBinder binder) { + mContext = null; mCallbackStub = null; - mISessionCallback = ISessionCallback.Stub.asInterface(in.readStrongBinder()); + mISessionCallback = ISessionCallback.Stub.asInterface(binder); } /** @@ -64,6 +74,7 @@ public final class SessionCallbackLink implements Parcelable { * @param args the arguments included with the command * @param cb the result receiver for getting the result of the command */ + @RequiresPermission(Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifyCommand(@NonNull String packageName, int pid, int uid, @NonNull ControllerCallbackLink caller, @NonNull String command, @Nullable Bundle args, @Nullable ResultReceiver cb) { @@ -84,6 +95,7 @@ public final class SessionCallbackLink implements Parcelable { * @param sequenceNumber the sequence number of this call * @param cb the result receiver for getting the result of the command */ + @RequiresPermission(Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifyMediaButton(@NonNull String packageName, int pid, int uid, @NonNull Intent mediaButtonIntent, int sequenceNumber, @Nullable ResultReceiver cb) { @@ -104,6 +116,7 @@ public final class SessionCallbackLink implements Parcelable { * @param caller the {@link ControllerCallbackLink} of the controller * @param mediaButtonIntent the media button intent */ + @RequiresPermission(Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifyMediaButtonFromController(@NonNull String packageName, int pid, int uid, @NonNull ControllerCallbackLink caller, @NonNull Intent mediaButtonIntent) { try { @@ -122,6 +135,7 @@ public final class SessionCallbackLink implements Parcelable { * @param uid the uid of the controller * @param caller the {@link ControllerCallbackLink} of the controller */ + @RequiresPermission(Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifyPrepare(@NonNull String packageName, int pid, int uid, @NonNull ControllerCallbackLink caller) { try { @@ -141,6 +155,7 @@ public final class SessionCallbackLink implements Parcelable { * @param mediaId the ID of the media * @param extras the extras included with this request. */ + @RequiresPermission(Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifyPrepareFromMediaId(@NonNull String packageName, int pid, int uid, @NonNull ControllerCallbackLink caller, @NonNull String mediaId, @Nullable Bundle extras) { @@ -162,6 +177,7 @@ public final class SessionCallbackLink implements Parcelable { * @param query the search query * @param extras the extras included with this request. */ + @RequiresPermission(Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifyPrepareFromSearch(@NonNull String packageName, int pid, int uid, @NonNull ControllerCallbackLink caller, @NonNull String query, @Nullable Bundle extras) { @@ -182,6 +198,7 @@ public final class SessionCallbackLink implements Parcelable { * @param uri the uri of the media * @param extras the extras included with this request. */ + @RequiresPermission(Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifyPrepareFromUri(@NonNull String packageName, int pid, int uid, @NonNull ControllerCallbackLink caller, @NonNull Uri uri, @Nullable Bundle extras) { try { @@ -199,6 +216,7 @@ public final class SessionCallbackLink implements Parcelable { * @param uid the uid of the controller * @param caller the {@link ControllerCallbackLink} of the controller */ + @RequiresPermission(Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifyPlay(@NonNull String packageName, int pid, int uid, @NonNull ControllerCallbackLink caller) { try { @@ -218,6 +236,7 @@ public final class SessionCallbackLink implements Parcelable { * @param mediaId the ID of the media * @param extras the extras included with this request. */ + @RequiresPermission(Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifyPlayFromMediaId(@NonNull String packageName, int pid, int uid, @NonNull ControllerCallbackLink caller, @NonNull String mediaId, @Nullable Bundle extras) { @@ -238,6 +257,7 @@ public final class SessionCallbackLink implements Parcelable { * @param query the search query * @param extras the extras included with this request. */ + @RequiresPermission(Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifyPlayFromSearch(@NonNull String packageName, int pid, int uid, @NonNull ControllerCallbackLink caller, @NonNull String query, @Nullable Bundle extras) { @@ -258,6 +278,7 @@ public final class SessionCallbackLink implements Parcelable { * @param uri the uri of the media * @param extras the extras included with this request. */ + @RequiresPermission(Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifyPlayFromUri(@NonNull String packageName, int pid, int uid, @NonNull ControllerCallbackLink caller, @NonNull Uri uri, @Nullable Bundle extras) { try { @@ -276,6 +297,7 @@ public final class SessionCallbackLink implements Parcelable { * @param caller the {@link ControllerCallbackLink} of the controller * @param id the queue id of the item */ + @RequiresPermission(Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifySkipToTrack(@NonNull String packageName, int pid, int uid, @NonNull ControllerCallbackLink caller, long id) { try { @@ -293,6 +315,7 @@ public final class SessionCallbackLink implements Parcelable { * @param uid the uid of the controller * @param caller the {@link ControllerCallbackLink} of the controller */ + @RequiresPermission(Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifyPause(@NonNull String packageName, int pid, int uid, @NonNull ControllerCallbackLink caller) { try { @@ -310,6 +333,7 @@ public final class SessionCallbackLink implements Parcelable { * @param uid the uid of the controller * @param caller the {@link ControllerCallbackLink} of the controller */ + @RequiresPermission(Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifyStop(@NonNull String packageName, int pid, int uid, @NonNull ControllerCallbackLink caller) { try { @@ -327,6 +351,7 @@ public final class SessionCallbackLink implements Parcelable { * @param uid the uid of the controller * @param caller the {@link ControllerCallbackLink} of the controller */ + @RequiresPermission(Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifyNext(@NonNull String packageName, int pid, int uid, @NonNull ControllerCallbackLink caller) { try { @@ -344,6 +369,7 @@ public final class SessionCallbackLink implements Parcelable { * @param uid the uid of the controller * @param caller the {@link ControllerCallbackLink} of the controller */ + @RequiresPermission(Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifyPrevious(@NonNull String packageName, int pid, int uid, @NonNull ControllerCallbackLink caller) { try { @@ -361,6 +387,7 @@ public final class SessionCallbackLink implements Parcelable { * @param uid the uid of the controller * @param caller the {@link ControllerCallbackLink} of the controller */ + @RequiresPermission(Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifyFastForward(@NonNull String packageName, int pid, int uid, @NonNull ControllerCallbackLink caller) { try { @@ -378,6 +405,7 @@ public final class SessionCallbackLink implements Parcelable { * @param uid the uid of the controller * @param caller the {@link ControllerCallbackLink} of the controller */ + @RequiresPermission(Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifyRewind(@NonNull String packageName, int pid, int uid, @NonNull ControllerCallbackLink caller) { try { @@ -396,6 +424,7 @@ public final class SessionCallbackLink implements Parcelable { * @param caller the {@link ControllerCallbackLink} of the controller * @param pos the position to move to, in milliseconds */ + @RequiresPermission(Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifySeekTo(@NonNull String packageName, int pid, int uid, @NonNull ControllerCallbackLink caller, long pos) { try { @@ -414,6 +443,7 @@ public final class SessionCallbackLink implements Parcelable { * @param caller the {@link ControllerCallbackLink} of the controller * @param rating the rating of the current media */ + @RequiresPermission(Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifyRate(@NonNull String packageName, int pid, int uid, @NonNull ControllerCallbackLink caller, @NonNull Rating rating) { try { @@ -433,6 +463,7 @@ public final class SessionCallbackLink implements Parcelable { * @param action the name of the action * @param args the arguments included with this action */ + @RequiresPermission(Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifyCustomAction(@NonNull String packageName, int pid, int uid, @NonNull ControllerCallbackLink caller, @NonNull String action, @Nullable Bundle args) { try { @@ -451,6 +482,7 @@ public final class SessionCallbackLink implements Parcelable { * @param caller the {@link ControllerCallbackLink} of the controller * @param direction the direction of the volume change. */ + @RequiresPermission(Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifyAdjustVolume(@NonNull String packageName, int pid, int uid, @NonNull ControllerCallbackLink caller, int direction) { try { @@ -469,6 +501,7 @@ public final class SessionCallbackLink implements Parcelable { * @param caller the {@link ControllerCallbackLink} of the controller * @param value the volume value to set */ + @RequiresPermission(Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifySetVolumeTo(@NonNull String packageName, int pid, int uid, @NonNull ControllerCallbackLink caller, int value) { try { @@ -498,7 +531,7 @@ public final class SessionCallbackLink implements Parcelable { new Parcelable.Creator<SessionCallbackLink>() { @Override public SessionCallbackLink createFromParcel(Parcel in) { - return new SessionCallbackLink(in); + return new SessionCallbackLink(in.readStrongBinder()); } @Override @@ -636,141 +669,296 @@ public final class SessionCallbackLink implements Parcelable { @Override public void notifyCommand(String packageName, int pid, int uid, ControllerCallbackLink caller, String command, Bundle args, ResultReceiver cb) { - mCallbackStub.onCommand(packageName, pid, uid, caller, command, args, cb); + ensureMediasControlPermission(); + final long token = Binder.clearCallingIdentity(); + try { + mCallbackStub.onCommand(packageName, pid, uid, caller, command, args, cb); + } finally { + Binder.restoreCallingIdentity(token); + } } @Override public void notifyMediaButton(String packageName, int pid, int uid, Intent mediaButtonIntent, int sequenceNumber, ResultReceiver cb) { - mCallbackStub.onMediaButton(packageName, pid, uid, mediaButtonIntent, sequenceNumber, - cb); + ensureMediasControlPermission(); + final long token = Binder.clearCallingIdentity(); + try { + mCallbackStub.onMediaButton(packageName, pid, uid, mediaButtonIntent, + sequenceNumber, cb); + } finally { + Binder.restoreCallingIdentity(token); + } } @Override public void notifyMediaButtonFromController(String packageName, int pid, int uid, ControllerCallbackLink caller, Intent mediaButtonIntent) { - mCallbackStub.onMediaButtonFromController(packageName, pid, uid, caller, - mediaButtonIntent); + ensureMediasControlPermission(); + final long token = Binder.clearCallingIdentity(); + try { + mCallbackStub.onMediaButtonFromController(packageName, pid, uid, caller, + mediaButtonIntent); + } finally { + Binder.restoreCallingIdentity(token); + } } @Override public void notifyPrepare(String packageName, int pid, int uid, ControllerCallbackLink caller) { - mCallbackStub.onPrepare(packageName, pid, uid, caller); + ensureMediasControlPermission(); + final long token = Binder.clearCallingIdentity(); + try { + mCallbackStub.onPrepare(packageName, pid, uid, caller); + } finally { + Binder.restoreCallingIdentity(token); + } } @Override public void notifyPrepareFromMediaId(String packageName, int pid, int uid, ControllerCallbackLink caller, String mediaId, Bundle extras) { - mCallbackStub.onPrepareFromMediaId(packageName, pid, uid, caller, mediaId, extras); + ensureMediasControlPermission(); + final long token = Binder.clearCallingIdentity(); + try { + mCallbackStub.onPrepareFromMediaId(packageName, pid, uid, caller, mediaId, extras); + } finally { + Binder.restoreCallingIdentity(token); + } } @Override public void notifyPrepareFromSearch(String packageName, int pid, int uid, ControllerCallbackLink caller, String query, Bundle extras) { - mCallbackStub.onPrepareFromSearch(packageName, pid, uid, caller, query, extras); + ensureMediasControlPermission(); + final long token = Binder.clearCallingIdentity(); + try { + mCallbackStub.onPrepareFromSearch(packageName, pid, uid, caller, query, extras); + } finally { + Binder.restoreCallingIdentity(token); + } } @Override public void notifyPrepareFromUri(String packageName, int pid, int uid, ControllerCallbackLink caller, Uri uri, Bundle extras) { - mCallbackStub.onPrepareFromUri(packageName, pid, uid, caller, uri, extras); + ensureMediasControlPermission(); + final long token = Binder.clearCallingIdentity(); + try { + mCallbackStub.onPrepareFromUri(packageName, pid, uid, caller, uri, extras); + } finally { + Binder.restoreCallingIdentity(token); + } } @Override public void notifyPlay(String packageName, int pid, int uid, ControllerCallbackLink caller) { - mCallbackStub.onPlay(packageName, pid, uid, caller); + ensureMediasControlPermission(); + final long token = Binder.clearCallingIdentity(); + try { + mCallbackStub.onPlay(packageName, pid, uid, caller); + } finally { + Binder.restoreCallingIdentity(token); + } } @Override public void notifyPlayFromMediaId(String packageName, int pid, int uid, ControllerCallbackLink caller, String mediaId, Bundle extras) { - mCallbackStub.onPlayFromMediaId(packageName, pid, uid, caller, mediaId, extras); + ensureMediasControlPermission(); + final long token = Binder.clearCallingIdentity(); + try { + mCallbackStub.onPlayFromMediaId(packageName, pid, uid, caller, mediaId, extras); + } finally { + Binder.restoreCallingIdentity(token); + } } @Override public void notifyPlayFromSearch(String packageName, int pid, int uid, ControllerCallbackLink caller, String query, Bundle extras) { - mCallbackStub.onPlayFromSearch(packageName, pid, uid, caller, query, extras); + ensureMediasControlPermission(); + final long token = Binder.clearCallingIdentity(); + try { + mCallbackStub.onPlayFromSearch(packageName, pid, uid, caller, query, extras); + } finally { + Binder.restoreCallingIdentity(token); + } } @Override public void notifyPlayFromUri(String packageName, int pid, int uid, ControllerCallbackLink caller, Uri uri, Bundle extras) { - mCallbackStub.onPlayFromUri(packageName, pid, uid, caller, uri, extras); + ensureMediasControlPermission(); + final long token = Binder.clearCallingIdentity(); + try { + mCallbackStub.onPlayFromUri(packageName, pid, uid, caller, uri, extras); + } finally { + Binder.restoreCallingIdentity(token); + } } @Override public void notifySkipToTrack(String packageName, int pid, int uid, ControllerCallbackLink caller, long id) { - mCallbackStub.onSkipToTrack(packageName, pid, uid, caller, id); + ensureMediasControlPermission(); + final long token = Binder.clearCallingIdentity(); + try { + mCallbackStub.onSkipToTrack(packageName, pid, uid, caller, id); + } finally { + Binder.restoreCallingIdentity(token); + } } @Override public void notifyPause(String packageName, int pid, int uid, ControllerCallbackLink caller) { - mCallbackStub.onPause(packageName, pid, uid, caller); + ensureMediasControlPermission(); + final long token = Binder.clearCallingIdentity(); + try { + mCallbackStub.onPause(packageName, pid, uid, caller); + } finally { + Binder.restoreCallingIdentity(token); + } } @Override public void notifyStop(String packageName, int pid, int uid, ControllerCallbackLink caller) { - mCallbackStub.onStop(packageName, pid, uid, caller); + ensureMediasControlPermission(); + final long token = Binder.clearCallingIdentity(); + try { + mCallbackStub.onStop(packageName, pid, uid, caller); + } finally { + Binder.restoreCallingIdentity(token); + } } @Override public void notifyNext(String packageName, int pid, int uid, ControllerCallbackLink caller) { - mCallbackStub.onNext(packageName, pid, uid, caller); + ensureMediasControlPermission(); + final long token = Binder.clearCallingIdentity(); + try { + mCallbackStub.onNext(packageName, pid, uid, caller); + } finally { + Binder.restoreCallingIdentity(token); + } } @Override public void notifyPrevious(String packageName, int pid, int uid, ControllerCallbackLink caller) { - mCallbackStub.onPrevious(packageName, pid, uid, caller); + ensureMediasControlPermission(); + final long token = Binder.clearCallingIdentity(); + try { + mCallbackStub.onPrevious(packageName, pid, uid, caller); + } finally { + Binder.restoreCallingIdentity(token); + } } @Override public void notifyFastForward(String packageName, int pid, int uid, ControllerCallbackLink caller) { - mCallbackStub.onFastForward(packageName, pid, uid, caller); + ensureMediasControlPermission(); + final long token = Binder.clearCallingIdentity(); + try { + mCallbackStub.onFastForward(packageName, pid, uid, caller); + } finally { + Binder.restoreCallingIdentity(token); + } } @Override public void notifyRewind(String packageName, int pid, int uid, ControllerCallbackLink caller) { - mCallbackStub.onRewind(packageName, pid, uid, caller); + ensureMediasControlPermission(); + final long token = Binder.clearCallingIdentity(); + try { + mCallbackStub.onRewind(packageName, pid, uid, caller); + } finally { + Binder.restoreCallingIdentity(token); + } } @Override public void notifySeekTo(String packageName, int pid, int uid, ControllerCallbackLink caller, long pos) { - mCallbackStub.onSeekTo(packageName, pid, uid, caller, pos); + ensureMediasControlPermission(); + final long token = Binder.clearCallingIdentity(); + try { + mCallbackStub.onSeekTo(packageName, pid, uid, caller, pos); + } finally { + Binder.restoreCallingIdentity(token); + } } @Override public void notifyRate(String packageName, int pid, int uid, ControllerCallbackLink caller, Rating rating) { - mCallbackStub.onRate(packageName, pid, uid, caller, rating); + ensureMediasControlPermission(); + final long token = Binder.clearCallingIdentity(); + try { + mCallbackStub.onRate(packageName, pid, uid, caller, rating); + } finally { + Binder.restoreCallingIdentity(token); + } } - @Override public void notifyCustomAction(String packageName, int pid, int uid, ControllerCallbackLink caller, String action, Bundle args) { - mCallbackStub.onCustomAction(packageName, pid, uid, caller, action, args); + ensureMediasControlPermission(); + final long token = Binder.clearCallingIdentity(); + try { + mCallbackStub.onCustomAction(packageName, pid, uid, caller, action, args); + } finally { + Binder.restoreCallingIdentity(token); + } } @Override public void notifyAdjustVolume(String packageName, int pid, int uid, ControllerCallbackLink caller, int direction) { - mCallbackStub.onAdjustVolume(packageName, pid, uid, caller, direction); + ensureMediasControlPermission(); + final long token = Binder.clearCallingIdentity(); + try { + mCallbackStub.onAdjustVolume(packageName, pid, uid, caller, direction); + } finally { + Binder.restoreCallingIdentity(token); + } } @Override public void notifySetVolumeTo(String packageName, int pid, int uid, ControllerCallbackLink caller, int value) { - mCallbackStub.onSetVolumeTo(packageName, pid, uid, caller, value); + ensureMediasControlPermission(); + final long token = Binder.clearCallingIdentity(); + try { + mCallbackStub.onSetVolumeTo(packageName, pid, uid, caller, value); + } finally { + Binder.restoreCallingIdentity(token); + } + } + + private void ensureMediasControlPermission() { + // Allow API calls from the System UI + if (mContext.checkCallingPermission(android.Manifest.permission.STATUS_BAR_SERVICE) + == PackageManager.PERMISSION_GRANTED) { + return; + } + + // Check if it's system server or has MEDIA_CONTENT_CONTROL. + // Note that system server doesn't have MEDIA_CONTENT_CONTROL, so we need extra + // check here. + if (getCallingUid() == Process.SYSTEM_UID || mContext.checkCallingPermission( + android.Manifest.permission.MEDIA_CONTENT_CONTROL) + == PackageManager.PERMISSION_GRANTED) { + return; + } + throw new SecurityException("Must hold the MEDIA_CONTENT_CONTROL permission."); } } } diff --git a/media/java/android/media/session/SessionLink.aidl b/media/java/android/media/session/SessionLink.aidl new file mode 100644 index 000000000000..c3be23e8f6b7 --- /dev/null +++ b/media/java/android/media/session/SessionLink.aidl @@ -0,0 +1,19 @@ +/* + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.media.session; + +parcelable SessionLink; diff --git a/media/java/android/media/session/SessionLink.java b/media/java/android/media/session/SessionLink.java new file mode 100644 index 000000000000..466077ebc1b7 --- /dev/null +++ b/media/java/android/media/session/SessionLink.java @@ -0,0 +1,453 @@ +/* + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.media.session; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.SystemApi; +import android.app.PendingIntent; +import android.media.AudioAttributes; +import android.media.MediaMetadata; +import android.media.Rating; +import android.media.VolumeProvider; +import android.media.session.MediaSession.QueueItem; +import android.os.Bundle; +import android.os.IBinder; +import android.os.Parcel; +import android.os.Parcelable; +import android.os.RemoteException; + +import java.util.List; + +/** + * Handles incoming commands from {@link MediaSession}. + * @hide + */ +@SystemApi +public final class SessionLink implements Parcelable { + public static final Parcelable.Creator<SessionLink> CREATOR = + new Parcelable.Creator<SessionLink>() { + @Override + public SessionLink createFromParcel(Parcel in) { + return new SessionLink(in.readStrongBinder()); + } + + @Override + public SessionLink[] newArray(int size) { + return new SessionLink[size]; + } + }; + + final SessionStub mSessionStub; + final ISession mISession; + + /** + * Constructor for stub (Callee) + */ + public SessionLink(@NonNull SessionStub sessionStub) { + mSessionStub = sessionStub; + mISession = new StubProxy(); + } + + /** + * Constructor for interface (Caller) + */ + public SessionLink(IBinder binder) { + mSessionStub = null; + mISession = ISession.Stub.asInterface(binder); + } + + /** + * Tell system that the session sends an event to all the connected controllers. + * + * @param event the name of the event + * @param extras the extras included with the event + */ + void sendEvent(@NonNull String event, @Nullable Bundle extras) { + try { + mISession.sendEvent(event, extras); + } catch (RemoteException e) { + throw new RuntimeException(e); + } + } + + /** + * Gets the controller link from the system. + */ + @NonNull + ControllerLink getController() { + try { + return mISession.getController(); + } catch (RemoteException e) { + throw new RuntimeException(e); + } + } + + /** + * Tell system that the session sets the flags. + * + * @param flags the new session flags + */ + void setFlags(int flags) { + try { + mISession.setFlags(flags); + } catch (RemoteException e) { + throw new RuntimeException(e); + } + } + + /** + * Tell system that the session is (in)active. + * + * @param active the new activeness state + */ + void setActive(boolean active) { + try { + mISession.setActive(active); + } catch (RemoteException e) { + throw new RuntimeException(e); + } + } + + /** + * Tell system that the session sets the media button receiver. + * + * @param mbr the pending intent for media button receiver + */ + void setMediaButtonReceiver(@Nullable PendingIntent mbr) { + try { + mISession.setMediaButtonReceiver(mbr); + } catch (RemoteException e) { + throw new RuntimeException(e); + } + } + + /** + * Tell system that the session sets the pending intent for launching UI. + * + * @param pi the pending intent for launching UI + */ + void setLaunchPendingIntent(@Nullable PendingIntent pi) { + try { + mISession.setLaunchPendingIntent(pi); + } catch (RemoteException e) { + throw new RuntimeException(e); + } + } + + /** + * Tell system that the session is destroyed. + */ + void destroySession() { + try { + mISession.destroySession(); + } catch (RemoteException e) { + throw new RuntimeException(e); + } + } + + /** + * Tell system that the session sets the new metadata. + * + * @param metadata the new metadata + * @param duration the duration of the media in milliseconds + * @param metadataDescription the description of the metadata + */ + void setMetadata(@Nullable MediaMetadata metadata, long duration, + @Nullable String metadataDescription) { + try { + mISession.setMetadata(metadata, duration, metadataDescription); + } catch (RemoteException e) { + throw new RuntimeException(e); + } + } + + /** + * Tell system that the session sets the new playback state. + * + * @param state the new playback state + */ + void setPlaybackState(@Nullable PlaybackState state) { + try { + mISession.setPlaybackState(state); + } catch (RemoteException e) { + throw new RuntimeException(e); + } + } + + /** + * Tell system that the session sets the new queue. + * + * @param queue the new queue + */ + void setQueue(@Nullable List<QueueItem> queue) { + try { + mISession.setQueue(queue); + } catch (RemoteException e) { + throw new RuntimeException(e); + } + } + + /** + * Tell system that the session sets the new queue title. + * + * @param title the new queue title + */ + void setQueueTitle(@Nullable CharSequence title) { + try { + mISession.setQueueTitle(title); + } catch (RemoteException e) { + throw new RuntimeException(e); + } + } + + /** + * Tell system that the session sets the new extras. + * + * @param extras the new extras + */ + void setExtras(@Nullable Bundle extras) { + try { + mISession.setExtras(extras); + } catch (RemoteException e) { + throw new RuntimeException(e); + } + } + + /** + * Tell system that the session sets the new rating type of the current media. + * + * @param type the rating type. + */ + void setRatingType(@Rating.Style int type) { + try { + mISession.setRatingType(type); + } catch (RemoteException e) { + throw new RuntimeException(e); + } + } + + /** + * Tell system that the session represents a local playback. + * + * @param attributes the audio attributes of the local playback. + */ + void setPlaybackToLocal(@NonNull AudioAttributes attributes) { + try { + mISession.setPlaybackToLocal(attributes); + } catch (RemoteException e) { + throw new RuntimeException(e); + } + } + + /** + * Tell system that the session represents a remote playback. + * + * @param control the volume control type + * @param max the max volume + */ + void setPlaybackToRemote(@VolumeProvider.ControlType int control, int max) { + try { + mISession.setPlaybackToRemote(control, max); + } catch (RemoteException e) { + throw new RuntimeException(e); + } + } + + /** + * Tell system that the session sets the new current volume. + * + * @param currentVolume the new current volume + */ + void setCurrentVolume(int currentVolume) { + try { + mISession.setCurrentVolume(currentVolume); + } catch (RemoteException e) { + throw new RuntimeException(e); + } + } + + /** Gets the binder */ + @NonNull + public IBinder getBinder() { + return mISession.asBinder(); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeStrongBinder(mISession.asBinder()); + } + + /** + * Class for Stub implementation + */ + public abstract static class SessionStub { + /** Stub method for ISession.sendEvent */ + public void sendEvent(@NonNull String event, @Nullable Bundle data) { + } + + /** Stub method for ISession.getController */ + @NonNull + public ControllerLink getController() { + return null; + } + + /** Stub method for ISession.setFlags */ + public void setFlags(int flags) { + } + + /** Stub method for ISession.setActive */ + public void setActive(boolean active) { + } + + /** Stub method for ISession.setMediaButtonReceiver */ + public void setMediaButtonReceiver(@Nullable PendingIntent mbr) { + } + + /** Stub method for ISession.setLaunchPendingIntent */ + public void setLaunchPendingIntent(@Nullable PendingIntent pi) { + } + + /** Stub method for ISession.destroySession */ + public void destroySession() { + } + + /** Stub method for ISession.setMetadata */ + public void setMetadata(@Nullable MediaMetadata metadata, long duration, + @Nullable String metadataDescription) { + } + + /** Stub method for ISession.setPlaybackState */ + public void setPlaybackState(@Nullable PlaybackState state) { + } + + /** Stub method for ISession.setQueue */ + public void setQueue(@Nullable List<QueueItem> queue) { + } + + /** Stub method for ISession.setQueueTitle */ + public void setQueueTitle(@Nullable CharSequence title) { + } + + /** Stub method for ISession.setExtras */ + public void setExtras(@Nullable Bundle extras) { + } + + /** Stub method for ISession.setRatingType */ + public void setRatingType(int type) { + } + + /** Stub method for ISession.setPlaybackToLocal */ + public void setPlaybackToLocal(@NonNull AudioAttributes attributes) { + } + + /** Stub method for ISession.setPlaybackToRemote */ + public void setPlaybackToRemote(int control, int max) { + } + + /** Stub method for ISession.setCurrentVolume */ + public void setCurrentVolume(int currentVolume) { + } + } + + private class StubProxy extends ISession.Stub { + @Override + public void sendEvent(String event, Bundle data) { + mSessionStub.sendEvent(event, data); + } + + @Override + public ControllerLink getController() { + return mSessionStub.getController(); + } + + @Override + public void setFlags(int flags) { + mSessionStub.setFlags(flags); + } + + @Override + public void setActive(boolean active) { + mSessionStub.setActive(active); + } + + @Override + public void setMediaButtonReceiver(PendingIntent mbr) { + mSessionStub.setMediaButtonReceiver(mbr); + } + + @Override + public void setLaunchPendingIntent(PendingIntent pi) { + mSessionStub.setLaunchPendingIntent(pi); + } + + @Override + public void destroySession() { + mSessionStub.destroySession(); + } + + @Override + public void setMetadata(MediaMetadata metadata, long duration, String metadataDescription) { + mSessionStub.setMetadata(metadata, duration, metadataDescription); + } + + @Override + public void setPlaybackState(PlaybackState state) { + mSessionStub.setPlaybackState(state); + } + + @Override + public void setQueue(List<QueueItem> queue) { + mSessionStub.setQueue(queue); + } + + @Override + public void setQueueTitle(CharSequence title) { + mSessionStub.setQueueTitle(title); + } + + @Override + public void setExtras(Bundle extras) { + mSessionStub.setExtras(extras); + } + + @Override + public void setRatingType(int type) { + mSessionStub.setRatingType(type); + } + + @Override + public void setPlaybackToLocal(AudioAttributes attributes) { + mSessionStub.setPlaybackToLocal(attributes); + } + + @Override + public void setPlaybackToRemote(int control, int max) { + mSessionStub.setPlaybackToRemote(control, max); + } + + @Override + public void setCurrentVolume(int currentVolume) { + mSessionStub.setCurrentVolume(currentVolume); + } + } +} diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java index 7fffe8eb402a..d8c2432db856 100644 --- a/services/core/java/com/android/server/media/MediaSessionRecord.java +++ b/services/core/java/com/android/server/media/MediaSessionRecord.java @@ -27,14 +27,14 @@ import android.media.MediaMetadata; import android.media.Rating; import android.media.VolumeProvider; import android.media.session.ControllerCallbackLink; -import android.media.session.ISession; -import android.media.session.ISessionController; +import android.media.session.ControllerLink; import android.media.session.MediaController; import android.media.session.MediaController.PlaybackInfo; import android.media.session.MediaSession; import android.media.session.MediaSession.QueueItem; import android.media.session.PlaybackState; import android.media.session.SessionCallbackLink; +import android.media.session.SessionLink; import android.net.Uri; import android.os.Binder; import android.os.Bundle; @@ -77,8 +77,8 @@ public class MediaSessionRecord implements IBinder.DeathRecipient { private final int mUserId; private final String mPackageName; private final String mTag; - private final ControllerStub mController; - private final SessionStub mSession; + private final ControllerLink mController; + private final SessionLink mSession; private final SessionCb mSessionCb; private final MediaSessionService.ServiceImpl mService; private final Context mContext; @@ -127,8 +127,8 @@ public class MediaSessionRecord implements IBinder.DeathRecipient { mUserId = userId; mPackageName = ownerPackageName; mTag = tag; - mController = new ControllerStub(); - mSession = new SessionStub(); + mController = new ControllerLink(new ControllerStub()); + mSession = new SessionLink(new SessionStub()); mSessionCb = new SessionCb(cb); mService = service; mContext = mService.getContext(); @@ -139,20 +139,20 @@ public class MediaSessionRecord implements IBinder.DeathRecipient { } /** - * Get the binder for the {@link MediaSession}. + * Get the session link for the {@link MediaSession}. * - * @return The session binder apps talk to. + * @return The session link apps talk to. */ - public ISession getSessionBinder() { + public SessionLink getSessionBinder() { return mSession; } /** - * Get the binder for the {@link MediaController}. + * Get the controller link for the {@link MediaController}. * - * @return The controller binder apps talk to. + * @return The controller link apps talk to. */ - public ISessionController getControllerBinder() { + public ControllerLink getControllerLink() { return mController; } @@ -642,7 +642,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient { if (mDestroyed) { return; } - PlaybackInfo info = mController.getVolumeAttributes(); + PlaybackInfo info = getVolumeAttributes(); for (int i = mControllerCallbackHolders.size() - 1; i >= 0; i--) { ControllerCallbackLinkHolder holder = mControllerCallbackHolders.get(i); try { @@ -750,6 +750,25 @@ public class MediaSessionRecord implements IBinder.DeathRecipient { return -1; } + private PlaybackInfo getVolumeAttributes() { + int volumeType; + AudioAttributes attributes; + synchronized (mLock) { + if (mVolumeType == PlaybackInfo.PLAYBACK_TYPE_REMOTE) { + int current = mOptimisticVolume != -1 ? mOptimisticVolume : mCurrentVolume; + return new PlaybackInfo(mVolumeType, mVolumeControlType, mMaxVolume, current, + mAudioAttrs); + } + volumeType = mVolumeType; + attributes = mAudioAttrs; + } + int stream = AudioAttributes.toLegacyStreamType(attributes); + int max = mAudioManager.getStreamMaxVolume(stream); + int current = mAudioManager.getStreamVolume(stream); + return new PlaybackInfo(volumeType, VolumeProvider.VOLUME_CONTROL_ABSOLUTE, max, + current, attributes); + } + private final Runnable mClearOptimisticVolumeRunnable = new Runnable() { @Override public void run() { @@ -761,9 +780,9 @@ public class MediaSessionRecord implements IBinder.DeathRecipient { } }; - private final class SessionStub extends ISession.Stub { + private final class SessionStub extends SessionLink.SessionStub { @Override - public void destroy() { + public void destroySession() { final long token = Binder.clearCallingIdentity(); try { mService.destroySession(MediaSessionRecord.this); @@ -779,7 +798,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient { } @Override - public ISessionController getController() { + public ControllerLink getController() { return mController; } @@ -798,8 +817,8 @@ public class MediaSessionRecord implements IBinder.DeathRecipient { @Override public void setFlags(int flags) { if ((flags & MediaSession.FLAG_EXCLUSIVE_GLOBAL_PRIORITY) != 0) { - int pid = getCallingPid(); - int uid = getCallingUid(); + int pid = Binder.getCallingPid(); + int uid = Binder.getCallingUid(); mService.enforcePhoneStatePermission(pid, uid); } mFlags = flags; @@ -1183,7 +1202,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient { } } - class ControllerStub extends ISessionController.Stub { + class ControllerStub extends ControllerLink.ControllerStub { @Override public void sendCommand(String packageName, ControllerCallbackLink caller, String command, Bundle args, ResultReceiver cb) { @@ -1199,7 +1218,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient { } @Override - public void registerCallbackListener(String packageName, ControllerCallbackLink cb) { + public void registerCallback(String packageName, ControllerCallbackLink cb) { synchronized (mLock) { // If this session is already destroyed tell the caller and // don't add them. @@ -1223,7 +1242,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient { } @Override - public void unregisterCallbackListener(ControllerCallbackLink cb) { + public void unregisterCallback(ControllerCallbackLink cb) { synchronized (mLock) { int index = getControllerHolderIndexForCb(cb); if (index != -1) { @@ -1257,22 +1276,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient { @Override public PlaybackInfo getVolumeAttributes() { - int volumeType; - AudioAttributes attributes; - synchronized (mLock) { - if (mVolumeType == PlaybackInfo.PLAYBACK_TYPE_REMOTE) { - int current = mOptimisticVolume != -1 ? mOptimisticVolume : mCurrentVolume; - return new PlaybackInfo(mVolumeType, mVolumeControlType, mMaxVolume, current, - mAudioAttrs); - } - volumeType = mVolumeType; - attributes = mAudioAttrs; - } - int stream = AudioAttributes.toLegacyStreamType(attributes); - int max = mAudioManager.getStreamMaxVolume(stream); - int current = mAudioManager.getStreamVolume(stream); - return new PlaybackInfo(volumeType, VolumeProvider.VOLUME_CONTROL_ABSOLUTE, max, - current, attributes); + return MediaSessionRecord.this.getVolumeAttributes(); } @Override @@ -1449,11 +1453,6 @@ public class MediaSessionRecord implements IBinder.DeathRecipient { public int getRatingType() { return mRatingType; } - - @Override - public boolean isTransportControlEnabled() { - return MediaSessionRecord.this.isTransportControlEnabled(); - } } private class ControllerCallbackLinkHolder { diff --git a/services/core/java/com/android/server/media/MediaSessionServiceImpl.java b/services/core/java/com/android/server/media/MediaSessionServiceImpl.java index f374c6d204fd..e3ae8a7ac21f 100644 --- a/services/core/java/com/android/server/media/MediaSessionServiceImpl.java +++ b/services/core/java/com/android/server/media/MediaSessionServiceImpl.java @@ -45,16 +45,18 @@ import android.media.IRemoteVolumeController; import android.media.MediaController2; import android.media.Session2CommandGroup; import android.media.Session2Token; +import android.media.session.ControllerLink; import android.media.session.IActiveSessionsListener; import android.media.session.ICallback; import android.media.session.IOnMediaKeyListener; import android.media.session.IOnVolumeKeyLongPressListener; -import android.media.session.ISession; import android.media.session.ISession2TokensListener; +import android.media.session.ISessionController; import android.media.session.ISessionManager; import android.media.session.MediaSession; import android.media.session.MediaSessionManager; import android.media.session.SessionCallbackLink; +import android.media.session.SessionLink; import android.net.Uri; import android.os.Binder; import android.os.Bundle; @@ -288,7 +290,9 @@ public class MediaSessionServiceImpl extends MediaSessionService.ServiceImpl { return; } try { - mRvc.remoteVolumeChanged(session.getControllerBinder(), flags); + mRvc.remoteVolumeChanged( + ISessionController.Stub.asInterface(session.getControllerLink().getBinder()), + flags); } catch (Exception e) { Log.wtf(TAG, "Error sending volume change to system UI.", e); } @@ -614,7 +618,7 @@ public class MediaSessionServiceImpl extends MediaSessionService.ServiceImpl { int size = records.size(); ArrayList<MediaSession.Token> tokens = new ArrayList<MediaSession.Token>(); for (int i = 0; i < size; i++) { - tokens.add(new MediaSession.Token(records.get(i).getControllerBinder())); + tokens.add(new MediaSession.Token(records.get(i).getControllerLink())); } pushRemoteVolumeUpdateLocked(userId); for (int i = mSessionsListeners.size() - 1; i >= 0; i--) { @@ -641,7 +645,9 @@ public class MediaSessionServiceImpl extends MediaSessionService.ServiceImpl { return; } MediaSessionRecord record = user.mPriorityStack.getDefaultRemoteSession(userId); - mRvc.updateRemoteController(record == null ? null : record.getControllerBinder()); + mRvc.updateRemoteController(record == null ? null + : ISessionController.Stub.asInterface( + record.getControllerLink().getBinder())); } catch (RemoteException e) { Log.wtf(TAG, "Error sending default remote volume to sys ui.", e); } @@ -858,7 +864,7 @@ public class MediaSessionServiceImpl extends MediaSessionService.ServiceImpl { MediaSessionRecord mediaButtonSession = getMediaButtonSessionLocked(); if (mediaButtonSession != null) { mCallback.onAddressedPlayerChangedToMediaSession( - new MediaSession.Token(mediaButtonSession.getControllerBinder())); + new MediaSession.Token(mediaButtonSession.getControllerLink())); } else if (mCurrentFullUserRecord.mLastMediaButtonReceiver != null) { mCallback.onAddressedPlayerChangedToMediaButtonReceiver( mCurrentFullUserRecord.mLastMediaButtonReceiver @@ -978,7 +984,7 @@ public class MediaSessionServiceImpl extends MediaSessionService.ServiceImpl { private boolean mVoiceButtonHandled = false; @Override - public ISession createSession(String packageName, SessionCallbackLink cb, String tag, + public SessionLink createSession(String packageName, SessionCallbackLink cb, String tag, int userId) throws RemoteException { final int pid = Binder.getCallingPid(); final int uid = Binder.getCallingUid(); @@ -1023,18 +1029,18 @@ public class MediaSessionServiceImpl extends MediaSessionService.ServiceImpl { } @Override - public List<IBinder> getSessions(ComponentName componentName, int userId) { + public List<ControllerLink> getSessions(ComponentName componentName, int userId) { final int pid = Binder.getCallingPid(); final int uid = Binder.getCallingUid(); final long token = Binder.clearCallingIdentity(); try { int resolvedUserId = verifySessionsRequest(componentName, userId, pid, uid); - ArrayList<IBinder> binders = new ArrayList<IBinder>(); + ArrayList<ControllerLink> binders = new ArrayList<>(); synchronized (mLock) { List<MediaSessionRecord> records = getActiveSessionsLocked(resolvedUserId); for (MediaSessionRecord record : records) { - binders.add(record.getControllerBinder().asBinder()); + binders.add(record.getControllerLink()); } } return binders; @@ -1798,7 +1804,7 @@ public class MediaSessionServiceImpl extends MediaSessionService.ServiceImpl { if (mCurrentFullUserRecord.mCallback != null) { try { mCurrentFullUserRecord.mCallback.onMediaKeyEventDispatchedToMediaSession( - keyEvent, new MediaSession.Token(session.getControllerBinder())); + keyEvent, new MediaSession.Token(session.getControllerLink())); } catch (RemoteException e) { Log.w(TAG, "Failed to send callback", e); } |