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

Commit c81e4db8 authored by Hyundo Moon's avatar Hyundo Moon
Browse files

MediaSession2: Implement setPlayer

This CL makes controller's onPlaybackInfoChanged() be called whenever
the session calls setPlayer().
Also, it replaces all usages of VolumeProvider with VolumeProvider2.

Bug: 72616099
Test: Passed MediaSession2Test
Change-Id: I51f48f49e8d2ee369571de0ef48353750a0612be
parent 5b95b0dd
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -31,6 +31,7 @@ oneway interface IMediaSession2Callback {
    void onPlaybackStateChanged(in Bundle state);
    void onPlaylistChanged(in List<Bundle> playlist);
    void onPlaylistParamsChanged(in Bundle params);
    void onPlaybackInfoChanged(in Bundle playbackInfo);

    /**
     * Called only when the controller is created with service's token.
+34 −6
Original line number Diff line number Diff line
@@ -74,6 +74,8 @@ public class MediaController2Impl implements MediaController2Provider {
    private List<MediaItem2> mPlaylist;
    @GuardedBy("mLock")
    private PlaylistParams mPlaylistParams;
    @GuardedBy("mLock")
    private PlaybackInfo mPlaybackInfo;

    // Assignment should be used with the lock hold, but should be used without a lock to prevent
    // potential deadlock.
@@ -292,12 +294,6 @@ public class MediaController2Impl implements MediaController2Provider {
        // TODO(jaewan): Implement
    }

    @Override
    public PlaybackInfo getPlaybackInfo_impl() {
        // TODO(jaewan): Implement
        return null;
    }

    @Override
    public void prepareFromUri_impl(Uri uri, Bundle extras) {
        // TODO(jaewan): Implement
@@ -412,6 +408,13 @@ public class MediaController2Impl implements MediaController2Provider {
        }
    }

    @Override
    public PlaybackInfo getPlaybackInfo_impl() {
        synchronized (mLock) {
            return mPlaybackInfo;
        }
    }

    @Override
    public void setPlaylistParams_impl(PlaylistParams params) {
        if (params == null) {
@@ -449,6 +452,18 @@ public class MediaController2Impl implements MediaController2Provider {
        });
    }

    private void pushPlaybackInfoChanges(final PlaybackInfo info) {
        synchronized (mLock) {
            mPlaybackInfo = info;
        }
        mCallbackExecutor.execute(() -> {
            if (!mInstance.isConnected()) {
                return;
            }
            mCallback.onPlaybackInfoChanged(info);
        });
    }

    private void pushPlaylistChanges(final List<Bundle> list) {
        final List<MediaItem2> playlist = new ArrayList<>();
        for (int i = 0; i < list.size(); i++) {
@@ -602,6 +617,19 @@ public class MediaController2Impl implements MediaController2Provider {
                    PlaylistParams.fromBundle(controller.getContext(), params));
        }

        @Override
        public void onPlaybackInfoChanged(Bundle playbackInfo) throws RuntimeException {
            final MediaController2Impl controller;
            try {
                controller = getController();
            } catch (IllegalStateException e) {
                Log.w(TAG, "Don't fail silently here. Highly likely a bug");
                return;
            }
            controller.pushPlaybackInfoChanges(
                    PlaybackInfoImpl.fromBundle(controller.getContext(), playbackInfo));
        }

        @Override
        public void onConnectionChanged(IMediaSession2 sessionBinder, Bundle commandGroup)
                throws RuntimeException {
+2 −2
Original line number Diff line number Diff line
@@ -28,7 +28,7 @@ import android.media.MediaSession2;
import android.media.MediaSession2.ControllerInfo;
import android.media.MediaSessionService2;
import android.media.SessionToken2;
import android.media.VolumeProvider;
import android.media.VolumeProvider2;
import android.media.update.MediaLibraryService2Provider;
import android.os.Bundle;

@@ -68,7 +68,7 @@ public class MediaLibraryService2Impl extends MediaSessionService2Impl implement
        private final MediaLibrarySessionCallback mCallback;

        public MediaLibrarySessionImpl(Context context,
                MediaPlayerInterface player, String id, VolumeProvider volumeProvider,
                MediaPlayerInterface player, String id, VolumeProvider2 volumeProvider,
                int ratingType, PendingIntent sessionActivity, Executor callbackExecutor,
                MediaLibrarySessionCallback callback) {
            super(context, player, id, volumeProvider, ratingType, sessionActivity,
+70 −16
Original line number Diff line number Diff line
@@ -21,15 +21,19 @@ import static android.media.SessionToken2.TYPE_LIBRARY_SERVICE;
import static android.media.SessionToken2.TYPE_SESSION;
import static android.media.SessionToken2.TYPE_SESSION_SERVICE;

import android.Manifest.permission;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.Manifest.permission;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
import android.media.AudioAttributes;
import android.media.AudioManager;
import android.media.MediaController2;
import android.media.MediaController2.PlaybackInfo;
import android.media.MediaItem2;
import android.media.MediaLibraryService2;
import android.media.MediaMetadata2;
@@ -48,14 +52,13 @@ import android.media.MediaSession2.SessionCallback;
import android.media.MediaSessionService2;
import android.media.PlaybackState2;
import android.media.SessionToken2;
import android.media.VolumeProvider;
import android.media.VolumeProvider2;
import android.media.session.MediaSessionManager;
import android.media.update.MediaSession2Provider;
import android.media.update.MediaSession2Provider.CommandButtonProvider;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Parcelable;
import android.os.Process;
import android.os.IBinder;
import android.os.ResultReceiver;
import android.support.annotation.GuardedBy;
import android.text.TextUtils;
@@ -80,11 +83,16 @@ public class MediaSession2Impl implements MediaSession2Provider {
    private final SessionCallback mCallback;
    private final MediaSession2Stub mSessionStub;
    private final SessionToken2 mSessionToken;
    private final AudioManager mAudioManager;
    private final List<PlaybackListenerHolder> mListeners = new ArrayList<>();

    @GuardedBy("mLock")
    private MediaPlayerInterface mPlayer;
    @GuardedBy("mLock")
    private VolumeProvider2 mVolumeProvider;
    @GuardedBy("mLock")
    private PlaybackInfo mPlaybackInfo;
    @GuardedBy("mLock")
    private MyPlaybackListener mListener;
    @GuardedBy("mLock")
    private PlaylistParams mPlaylistParams;
@@ -103,8 +111,8 @@ public class MediaSession2Impl implements MediaSession2Provider {
     * @param ratingType
     * @param sessionActivity
     */
    public MediaSession2Impl(Context context, MediaPlayerInterface player,
            String id, VolumeProvider volumeProvider, int ratingType, PendingIntent sessionActivity,
    public MediaSession2Impl(Context context, MediaPlayerInterface player, String id,
            VolumeProvider2 volumeProvider, int ratingType, PendingIntent sessionActivity,
            Executor callbackExecutor, SessionCallback callback) {
        // TODO(jaewan): Keep other params.
        mInstance = createInstance();
@@ -116,6 +124,7 @@ public class MediaSession2Impl implements MediaSession2Provider {
        mCallback = callback;
        mCallbackExecutor = callbackExecutor;
        mSessionStub = new MediaSession2Stub(this);
        mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);

        // Infer type from the id and package name.
        String libraryService = getServiceName(context, MediaLibraryService2.SERVICE_INTERFACE, id);
@@ -135,6 +144,8 @@ public class MediaSession2Impl implements MediaSession2Provider {
        }

        setPlayerLocked(player);
        mVolumeProvider = volumeProvider;
        mPlaybackInfo = createPlaybackInfo(volumeProvider, player.getAudioAttributes());

        // Ask server for the sanity check, and starts
        // Sanity check for making session ID unique 'per package' cannot be done in here.
@@ -178,22 +189,46 @@ public class MediaSession2Impl implements MediaSession2Provider {
        return serviceName;
    }

    // TODO(jaewan): Add explicit release() and do not remove session object with the
    //               setPlayer(null). Token can be available when player is null, and
    //               controller can also attach to session.
    @Override
    public void setPlayer_impl(MediaPlayerInterface player, VolumeProvider volumeProvider)
    public void setPlayer_impl(MediaPlayerInterface player) {
        ensureCallingThread();
        if (player == null) {
            throw new IllegalArgumentException("player shouldn't be null");
        }
        if (player == mPlayer) {
            return;
        }
        PlaybackInfo info =
                createPlaybackInfo(null /* VolumeProvider */, player.getAudioAttributes());
        synchronized (mLock) {
            setPlayerLocked(player);
            mVolumeProvider = null;
            mPlaybackInfo = info;
        }
        mSessionStub.notifyPlaybackInfoChanged(info);
    }

    @Override
    public void setPlayer_impl(MediaPlayerInterface player, VolumeProvider2 volumeProvider)
            throws IllegalArgumentException {
        ensureCallingThread();
        if (player == null) {
            throw new IllegalArgumentException("player shouldn't be null");
        }
        if (volumeProvider == null) {
            throw new IllegalArgumentException("volumeProvider shouldn't be null");
        }
        if (player == mPlayer) {
            return;
        }

        PlaybackInfo info = createPlaybackInfo(volumeProvider, player.getAudioAttributes());
        synchronized (mLock) {
            setPlayerLocked(player);
            mVolumeProvider = volumeProvider;
            mPlaybackInfo = info;
        }
        mSessionStub.notifyPlaybackInfoChanged(info);
    }

    private void setPlayerLocked(MediaPlayerInterface player) {
@@ -206,6 +241,29 @@ public class MediaSession2Impl implements MediaSession2Provider {
        player.addPlaybackListener(mCallbackExecutor, mListener);
    }

    private PlaybackInfo createPlaybackInfo(VolumeProvider2 volumeProvider, AudioAttributes attrs) {
        PlaybackInfo info;
        if (volumeProvider == null) {
            int stream = attrs == null ? AudioManager.STREAM_MUSIC : attrs.getVolumeControlStream();
            info = PlaybackInfoImpl.createPlaybackInfo(
                    mContext,
                    PlaybackInfo.PLAYBACK_TYPE_LOCAL,
                    attrs,
                    VolumeProvider2.VOLUME_CONTROL_ABSOLUTE,
                    mAudioManager.getStreamMaxVolume(stream),
                    mAudioManager.getStreamVolume(stream));
        } else {
            info = PlaybackInfoImpl.createPlaybackInfo(
                    mContext,
                    PlaybackInfo.PLAYBACK_TYPE_REMOTE /* ControlType */,
                    attrs,
                    volumeProvider.getControlType(),
                    volumeProvider.getMaxVolume(),
                    volumeProvider.getCurrentVolume());
        }
        return info;
    }

    @Override
    public void close_impl() {
        // Stop system service from listening this session first.
@@ -320,10 +378,6 @@ public class MediaSession2Impl implements MediaSession2Provider {
    //////////////////////////////////////////////////////////////////////////////////////
    // TODO(jaewan): Implement follows
    //////////////////////////////////////////////////////////////////////////////////////
    @Override
    public void setPlayer_impl(MediaPlayerInterface player) {
        // TODO(jaewan): Implement
    }

    @Override
    public void setAllowedCommands_impl(ControllerInfo controller, CommandGroup commands) {
@@ -1032,7 +1086,7 @@ public class MediaSession2Impl implements MediaSession2Provider {
        String mId;
        Executor mCallbackExecutor;
        C mCallback;
        VolumeProvider mVolumeProvider;
        VolumeProvider2 mVolumeProvider;
        int mRatingType;
        PendingIntent mSessionActivity;

@@ -1058,7 +1112,7 @@ public class MediaSession2Impl implements MediaSession2Provider {
            mId = "";
        }

        public void setVolumeProvider_impl(VolumeProvider volumeProvider) {
        public void setVolumeProvider_impl(VolumeProvider2 volumeProvider) {
            mVolumeProvider = volumeProvider;
        }

+17 −0
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package com.android.media;

import android.content.Context;
import android.media.MediaController2;
import android.media.MediaItem2;
import android.media.MediaLibraryService2.LibraryRoot;
import android.media.MediaLibraryService2.MediaLibrarySessionCallback;
@@ -130,6 +131,7 @@ public class MediaSession2Stub extends IMediaSession2.Stub {
                // Controller may be died prematurely.
            }
            if (accept) {
                // TODO(jaewan): We need to send current PlaybackInfo.
                // If connection is accepted, notify the current state to the controller.
                // It's needed because we cannot call synchronous calls between session/controller.
                // Note: We're doing this after the onConnectionChanged(), but there's no guarantee
@@ -390,6 +392,21 @@ public class MediaSession2Stub extends IMediaSession2.Stub {
        }
    }

    public void notifyPlaybackInfoChanged(MediaController2.PlaybackInfo playbackInfo) {
        final List<ControllerInfo> list = getControllers();
        for (int i = 0; i < list.size(); i++) {
            IMediaSession2Callback callbackBinder =
                    ControllerInfoImpl.from(list.get(i)).getControllerBinder();
            try {
                callbackBinder.onPlaybackInfoChanged(
                        ((PlaybackInfoImpl) playbackInfo.getProvider()).toBundle());
            } catch (RemoteException e) {
                Log.w(TAG, "Controller is gone", e);
                // TODO(jaewan): What to do when the controller is gone?
            }
        }
    }

    public void sendCustomCommand(ControllerInfo controller, Command command, Bundle args,
            ResultReceiver receiver) {
        if (receiver != null && controller == null) {
Loading