Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit aa846900 authored by Jaewan Kim's avatar Jaewan Kim Committed by android-build-merger
Browse files

MediaSession2: Implement get/setPlaylist()

am: e0a38c69

Change-Id: I74b94f51e78adc02d2e2d28a5edc57d04c79a8e4
parents 89a1bc1f e0a38c69
Loading
Loading
Loading
Loading
+5 −3
Original line number Diff line number Diff line
@@ -28,12 +28,12 @@ import com.android.media.IMediaSession2Callback;
 * Keep this interface oneway. Otherwise a malicious app may implement fake version of this,
 * and holds calls from session to make session owner(s) frozen.
 */
 // TODO(jaewan): (Post P) Handle when the playlist becomes too huge.
 //               Note that ParcelledSliceList isn't a good idea for the purpose. (see: b/37493677)
oneway interface IMediaSession2 {
    // TODO(jaewan): add onCommand() to send private command
    // TODO(jaewan): Due to the nature of oneway calls, APIs can be called in out of order
    //               Add id for individual calls to address this.

    // TODO(jaewan): We may consider to add another binder just for the connection
    // TODO(jaewan): (Post P) We may consider to add another binder just for the connection
    //               not to expose other methods to the controller whose connection wasn't accepted.
    //               But this would be enough for now because it's the same as existing
    //               MediaBrowser and MediaBrowserService.
@@ -59,6 +59,8 @@ oneway interface IMediaSession2 {
    void playFromMediaId(IMediaSession2Callback caller, String mediaId, in Bundle extras);
    void setRating(IMediaSession2Callback caller, String mediaId, in Bundle rating);

    void setPlaylist(IMediaSession2Callback caller, in List<Bundle> playlist, in Bundle metadata);

    //////////////////////////////////////////////////////////////////////////////////////////////
    // library service specific
    //////////////////////////////////////////////////////////////////////////////////////////////
+3 −2
Original line number Diff line number Diff line
@@ -28,13 +28,14 @@ import com.android.media.IMediaSession2;
 * Keep this interface oneway. Otherwise a malicious app may implement fake version of this,
 * and holds calls from session to make session owner(s) frozen.
 */
// TODO(jaewan): (Post P) Handle when the playlist becomes too huge.
//               Note that ParcelledSliceList isn't a good idea for the purpose. (see: b/37493677)
oneway interface IMediaSession2Callback {
    void onPlaybackStateChanged(in Bundle state);
    void onPlaylistChanged(in List<Bundle> playlist);
    void onPlaylistChanged(in List<Bundle> playlist, in Bundle metadata);
    void onPlaylistParamsChanged(in Bundle params);
    void onPlaybackInfoChanged(in Bundle playbackInfo);

    // TODO(jaewan): Handle when the playlist becomes too huge.
    void onConnected(IMediaSession2 sessionBinder, in Bundle commandGroup, in Bundle playbackState,
            in Bundle playbackInfo, in Bundle params, in List<Bundle> playlist,
            in PendingIntent sessionActivity);
+34 −7
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@ import android.media.MediaController2;
import android.media.MediaController2.ControllerCallback;
import android.media.MediaController2.PlaybackInfo;
import android.media.MediaItem2;
import android.media.MediaMetadata2;
import android.media.MediaSession2;
import android.media.MediaSession2.Command;
import android.media.MediaSession2.CommandButton;
@@ -76,6 +77,8 @@ public class MediaController2Impl implements MediaController2Provider {
    @GuardedBy("mLock")
    private List<MediaItem2> mPlaylist;
    @GuardedBy("mLock")
    private MediaMetadata2 mPlaylistMetadata;
    @GuardedBy("mLock")
    private PlaylistParams mPlaylistParams;
    @GuardedBy("mLock")
    private PlaybackInfo mPlaybackInfo;
@@ -525,6 +528,28 @@ public class MediaController2Impl implements MediaController2Provider {
        }
    }

    @Override
    public void setPlaylist_impl(List<MediaItem2> list, MediaMetadata2 metadata) {
        if (list == null) {
            throw new IllegalArgumentException("list shouldn't be null");
        }
        final IMediaSession2 binder = getSessionBinderIfAble(COMMAND_CODE_PLAYLIST_SET_LIST);
        if (binder != null) {
            List<Bundle> bundleList = new ArrayList<>();
            for (int i = 0; i < list.size(); i++) {
                bundleList.add(list.get(i).toBundle());
            }
            Bundle metadataBundle = (metadata == null) ? null : metadata.toBundle();
            try {
                binder.setPlaylist(mSessionCallbackStub, bundleList, metadataBundle);
            } catch (RemoteException e) {
                Log.w(TAG, "Cannot connect to the service or the session is gone", e);
            }
        } else {
            Log.w(TAG, "Session isn't active", new IllegalStateException());
        }
    }

    @Override
    public void prepare_impl() {
        sendTransportControlCommand(MediaSession2.COMMAND_CODE_PLAYBACK_PREPARE);
@@ -692,17 +717,19 @@ public class MediaController2Impl implements MediaController2Provider {
        });
    }

    void pushPlaylistChanges(final List<MediaItem2> playlist) {
    void pushPlaylistChanges(final List<MediaItem2> playlist, final MediaMetadata2 metadata) {
        synchronized (mLock) {
            mPlaylist = playlist;
            mPlaylistMetadata = metadata;
        }
        mCallbackExecutor.execute(() -> {
            if (!mInstance.isConnected()) {
                return;
            }
                mCallback.onPlaylistChanged(mInstance, playlist);
            // TODO(jaewan): Fix public API not to take playlistAgent.
            mCallback.onPlaylistChanged(mInstance, null, playlist, metadata);
        });
    }
    }

    // Should be used without a lock to prevent potential deadlock.
    void onConnectedNotLocked(IMediaSession2 sessionBinder,
+1 −1
Original line number Diff line number Diff line
@@ -228,7 +228,7 @@ public class MediaMetadata2Impl implements MediaMetadata2Provider {
    }

    public static MediaMetadata2 fromBundle(Context context, Bundle bundle) {
        return new MediaMetadata2Impl(context, bundle).getInstance();
        return (bundle == null) ? null : new MediaMetadata2Impl(context, bundle).getInstance();
    }

    public static final class BuilderImpl implements MediaMetadata2Provider.BuilderProvider {
+6 −3
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@ import android.app.PendingIntent;
import android.content.Context;
import android.media.MediaController2;
import android.media.MediaItem2;
import android.media.MediaMetadata2;
import android.media.MediaSession2.Command;
import android.media.MediaSession2.CommandButton;
import android.media.MediaSession2.CommandGroup;
@@ -81,7 +82,7 @@ public class MediaSession2CallbackStub extends IMediaSession2Callback.Stub {
    }

    @Override
    public void onPlaylistChanged(List<Bundle> playlistBundle) throws RuntimeException {
    public void onPlaylistChanged(List<Bundle> playlistBundle, Bundle metadataBundle) {
        final MediaController2Impl controller;
        try {
            controller = getController();
@@ -90,7 +91,7 @@ public class MediaSession2CallbackStub extends IMediaSession2Callback.Stub {
            return;
        }
        if (playlistBundle == null) {
            Log.w(TAG, "onPlaylistChanged(): Ignoring null playlist");
            Log.w(TAG, "onPlaylistChanged(): Ignoring null playlist from " + controller);
            return;
        }
        List<MediaItem2> playlist = new ArrayList<>();
@@ -102,7 +103,9 @@ public class MediaSession2CallbackStub extends IMediaSession2Callback.Stub {
                playlist.add(item);
            }
        }
        controller.pushPlaylistChanges(playlist);
        MediaMetadata2 metadata =
                MediaMetadata2.fromBundle(controller.getContext(), metadataBundle);
        controller.pushPlaylistChanges(playlist, metadata);
    }

    @Override
Loading