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

Commit 0d61a00c authored by Jaewan Kim's avatar Jaewan Kim
Browse files

MediaSession2: Add/remove playback listeners

Test: Run all MediaComponents test once
Change-Id: If88fa492d40f9d202e8bdfcebd06cd9b82554041
parent f7a7706d
Loading
Loading
Loading
Loading
+6 −27
Original line number Diff line number Diff line
@@ -24,9 +24,7 @@ import android.os.Bundle;
 *
 * @hide
 */
// TODO(jaewan): Make this oneway interface.
//               Malicious app can fake session binder and holds commands from controller.
interface IMediaSession2 {
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.
@@ -35,37 +33,18 @@ interface IMediaSession2 {
    //               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.
    oneway void connect(String callingPackage, IMediaSession2Callback callback);
    oneway void release(IMediaSession2Callback caller);
    void connect(String callingPackage, IMediaSession2Callback callback);
    void release(IMediaSession2Callback caller);

    //////////////////////////////////////////////////////////////////////////////////////////////
    // send command
    //////////////////////////////////////////////////////////////////////////////////////////////
    oneway void sendCommand(IMediaSession2Callback caller, in Bundle command, in Bundle args);
    oneway void sendTransportControlCommand(IMediaSession2Callback caller,
    void sendCommand(IMediaSession2Callback caller, in Bundle command, in Bundle args);
    void sendTransportControlCommand(IMediaSession2Callback caller,
            int commandCode, long arg);

    Bundle getPlaybackState();

    //////////////////////////////////////////////////////////////////////////////////////////////
    // Get library service specific
    //////////////////////////////////////////////////////////////////////////////////////////////
    oneway void getBrowserRoot(IMediaSession2Callback callback, in Bundle rootHints);

    //////////////////////////////////////////////////////////////////////////////////////////////
    // Callbacks -- remove them
    //////////////////////////////////////////////////////////////////////////////////////////////
    /**
     * @param callbackBinder binder to be used to notify changes.
     * @param callbackFlag one of {@link MediaController2#FLAG_CALLBACK_PLAYBACK} or
     *     {@link MediaController2#FLAG_CALLBACK_SESSION_ACTIVENESS}
     * @param requestCode If >= 0, this code will be called back by the callback after the callback
     *     is registered.
     */
    // TODO(jaewan): Due to the nature of the binder, calls can be called out of order.
    //               Need a way to ensure calling of unregisterCallback unregisters later
    //               registerCallback.
    oneway void registerCallback(IMediaSession2Callback callbackBinder,
            int callbackFlag, int requestCode);
    oneway void unregisterCallback(IMediaSession2Callback callbackBinder, int callbackFlag);
    void getBrowserRoot(IMediaSession2Callback callback, in Bundle rootHints);
}
+9 −5
Original line number Diff line number Diff line
@@ -133,9 +133,9 @@ public class MediaController2 implements AutoCloseable {
                @NonNull List<MediaItem2> list, @NonNull PlaylistParams param) { }

        /**
         * Called when the playback state is changed.
         * Called when the playback state is changed, or connection success.
         *
         * @param state
         * @param state latest playback state
         */
        public void onPlaybackStateChanged(@NonNull PlaybackState2 state) { }

@@ -546,11 +546,15 @@ public class MediaController2 implements AutoCloseable {
    }

    /**
     * Get the latest {@link PlaybackState2} from the session.
     * Get the lastly cached {@link PlaybackState2} from
     * {@link ControllerCallback#onPlaybackStateChanged(PlaybackState2)}.
     * <p>
     * It may return {@code null} before the first callback or session has sent {@code null}
     * playback state.
     *
     * @return a playback state
     * @return a playback state. Can be {@code null}
     */
    public PlaybackState2 getPlaybackState() {
    public @Nullable PlaybackState2 getPlaybackState() {
        return mProvider.getPlaybackState_impl();
    }

+37 −2
Original line number Diff line number Diff line
@@ -83,6 +83,7 @@ public class MediaSession2 implements AutoCloseable {

    // Note: Do not define IntDef because subclass can add more command code on top of these.
    // TODO(jaewan): Shouldn't we pull out?
    // TODO(jaewan): Should we also protect getPlaybackState()?
    public static final int COMMAND_CODE_CUSTOM = 0;
    public static final int COMMAND_CODE_PLAYBACK_START = 1;
    public static final int COMMAND_CODE_PLAYBACK_PAUSE = 2;
@@ -199,7 +200,8 @@ public class MediaSession2 implements AutoCloseable {
        @Override
        public int hashCode() {
            final int prime = 31;
            return ((mCustomCommand != null) ? mCustomCommand.hashCode() : 0) * prime + mCommandCode;
            return ((mCustomCommand != null)
                    ? mCustomCommand.hashCode() : 0) * prime + mCommandCode;
        }
    }

@@ -999,7 +1001,6 @@ public class MediaSession2 implements AutoCloseable {
     *       framework had to add heuristics to figure out if an app is
     * @hide
     */

    MediaSession2(Context context, MediaPlayerInterface player, String id,
            VolumeProvider volumeProvider, int ratingType, PendingIntent sessionActivity,
            Executor callbackExecutor, SessionCallback callback) {
@@ -1288,4 +1289,38 @@ public class MediaSession2 implements AutoCloseable {
    public PlaylistParams getPlaylistParams() {
        return mProvider.getPlaylistParams_impl();
    }

    /*
     * Add a {@link PlaybackListener} to listen changes in the underlying
     * {@link MediaPlayerInterface}. Listener will be called immediately to tell the current value.
     * <p>
     * Added listeners will be also called when the underlying player is changed.
     *
     * @param executor the call listener
     * @param listener the listener that will be run
     * @throws IllegalArgumentException when either the listener or handler is {@code null}.
     */
    public void addPlaybackListener(@NonNull @CallbackExecutor Executor executor,
            @NonNull PlaybackListener listener) {
        mProvider.addPlaybackListener_impl(executor, listener);
    }

    /**
     * Remove previously added {@link PlaybackListener}.
     *
     * @param listener the listener to be removed
     * @throws IllegalArgumentException if the listener is {@code null}.
     */
    public void removePlaybackListener(@NonNull PlaybackListener listener) {
        mProvider.removePlaybackListener_impl(listener);
    }

    /**
     * Return the {@link PlaybackState2} from the player.
     *
     * @return playback state
     */
    public PlaybackState2 getPlaybackState() {
        return mProvider.getPlaybackState_impl();
    }
}
+3 −0
Original line number Diff line number Diff line
@@ -108,6 +108,9 @@ public final class PlaybackState2 {
    private final long mActiveItemId;
    private final CharSequence mErrorMessage;

    // TODO(jaewan): Better error handling?
    //               E.g. media item at #2 has issue, but continue playing #3
    //                    login error. fire intent xxx to login
    public PlaybackState2(int state, long position, long updateTime, float speed,
            long bufferedPosition, long activeItemId, CharSequence error) {
        mState = state;
+5 −0
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ package android.media.update;
import android.media.AudioAttributes;
import android.media.MediaItem2;
import android.media.MediaPlayerInterface;
import android.media.MediaPlayerInterface.PlaybackListener;
import android.media.MediaSession2.Command;
import android.media.MediaSession2.CommandButton;
import android.media.MediaSession2.CommandGroup;
@@ -30,6 +31,7 @@ import android.os.Bundle;
import android.os.ResultReceiver;

import java.util.List;
import java.util.concurrent.Executor;

/**
 * @hide
@@ -56,6 +58,9 @@ public interface MediaSession2Provider extends TransportControlProvider {
    void setPlaylistParams_impl(PlaylistParams params);
    PlaylistParams getPlaylistParams_impl();

    void addPlaybackListener_impl(Executor executor, PlaybackListener listener);
    void removePlaybackListener_impl(PlaybackListener listener);

    interface ControllerInfoProvider {
        String getPackageName_impl();
        int getUid_impl();
Loading