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

Commit 938e8e91 authored by Sungsoo Lim's avatar Sungsoo Lim
Browse files

Add MediaSession2 builder and update JAVADOCs

Bug: 122055262
Test: build
Change-Id: I9cab65f9b09cbe5d5570e4de649ffdff09b20b80
parent f894f77d
Loading
Loading
Loading
Loading
+3 −2
Original line number Diff line number Diff line
@@ -39,8 +39,9 @@ import java.util.concurrent.Executor;
 * commands can be sent to the session.
 * <p>
 * This API is not generally intended for third party application developers.
 * Use the <a href="{@docRoot}tools/extras/support-library.html">Support Library</a>
 * {@link androidx.media2.MediaController} for consistent behavior across all devices.
 * Use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a>
 * <a href="{@docRoot}reference/androidx/media2/package-summary.html">Media2 Library</a>
 * for consistent behavior across all devices.
 * @hide
 */
public class MediaController2 implements AutoCloseable {
+3 −2
Original line number Diff line number Diff line
@@ -36,8 +36,9 @@ import java.util.concurrent.Executor;
 * A class with information on a single media item with the metadata information.
 * <p>
 * This API is not generally intended for third party application developers.
 * Use the <a href="{@docRoot}tools/extras/support-library.html">Support Library</a>
 * {@link androidx.media2.MediaItem} for consistent behavior across all devices.
 * Use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a>
 * <a href="{@docRoot}reference/androidx/media2/package-summary.html">Media2 Library</a>
 * for consistent behavior across all devices.
 * <p>
 * @hide
 */
+131 −19
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.media.session.MediaSessionManager;
import android.media.session.MediaSessionManager.RemoteUserInfo;
import android.os.Binder;
@@ -33,7 +34,9 @@ import android.os.Bundle;
import android.os.Process;
import android.util.Log;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.Executor;
@@ -43,14 +46,20 @@ import java.util.concurrent.Executor;
 * other processes including the Android framework and other apps.
 * <p>
 * This API is not generally intended for third party application developers.
 * Use the <a href="{@docRoot}tools/extras/support-library.html">Support Library</a>
 * {@link androidx.media2.MediaSession} for consistent behavior across all devices.
 * Use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a>
 * <a href="{@docRoot}reference/androidx/media2/package-summary.html">Media2 Library</a>
 * for consistent behavior across all devices.
 * @hide
 */
public class MediaSession2 implements AutoCloseable {
    static final String TAG = "MediaSession";
    static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);

    // Note: This checks the uniqueness of a session ID only in a single process.
    // When the framework becomes able to check the uniqueness, this logic should be removed.
    //@GuardedBy("MediaSession.class")
    private static final List<String> SESSION_ID_LIST = new ArrayList<>();

    @SuppressWarnings("WeakerAccess") /* synthetic access */
    final Object mLock = new Object();
    //@GuardedBy("mLock")
@@ -71,8 +80,15 @@ public class MediaSession2 implements AutoCloseable {
    private final Session2Token mSessionToken;
    private final MediaSessionManager mSessionManager;

    MediaSession2(Context context, String id, PendingIntent sessionActivity,
            Executor callbackExecutor, SessionCallback callback) {
    MediaSession2(@NonNull Context context, @NonNull String id, PendingIntent sessionActivity,
            @NonNull Executor callbackExecutor, @NonNull SessionCallback callback) {
        synchronized (MediaSession2.class) {
            if (SESSION_ID_LIST.contains(id)) {
                throw new IllegalStateException("Session ID must be unique. ID=" + id);
            }
            SESSION_ID_LIST.add(id);
        }

        mContext = context;
        mSessionId = id;
        mSessionActivity = sessionActivity;
@@ -87,16 +103,21 @@ public class MediaSession2 implements AutoCloseable {

    @Override
    public void close() throws Exception {
        try {
            synchronized (MediaSession2.class) {
                SESSION_ID_LIST.remove(mSessionId);
            }
            // TODO: Implement this
        } catch (Exception e) {
            // Should not be here.
        }
    }

    // AML method
    boolean isClosed() {
        // TODO: Implement this
        return true;
    }

    // AML method
    void onConnect(final Controller2Link controller, int seq, Bundle connectionRequest) {
        if (controller == null || connectionRequest == null) {
            return;
@@ -174,7 +195,6 @@ public class MediaSession2 implements AutoCloseable {
        }
    }

    // AML method
    void onDisconnect(final Controller2Link controller, int seq) {
        if (controller == null) {
            return;
@@ -197,12 +217,107 @@ public class MediaSession2 implements AutoCloseable {
        }
    }

    // AML method
    void onSessionCommand(final Controller2Link controller, final int seq,
            final Session2Command command, final Bundle args) {
        // TODO: Implement this
    }

    /**
     * Builder for {@link MediaSession2}.
     * <p>
     * Any incoming event from the {@link MediaController2} will be handled on the callback
     * executor. If it's not set, {@link Context#getMainExecutor()} will be used by default.
     */
    public static final class Builder {
        private Context mContext;
        private String mId;
        private PendingIntent mSessionActivity;
        private Executor mCallbackExecutor;
        private SessionCallback mCallback;

        /**
         * Creates a builder for {@link MediaSession2}.
         *
         * @param context Context
         * @throws IllegalArgumentException if context is {@code null}.
         */
        public Builder(@NonNull Context context) {
            if (context == null) {
                throw new IllegalArgumentException("context shouldn't be null");
            }
            mContext = context;
        }

        /**
         * Set an intent for launching UI for this Session. This can be used as a
         * quick link to an ongoing media screen. The intent should be for an
         * activity that may be started using {@link Context#startActivity(Intent)}.
         *
         * @param pi The intent to launch to show UI for this session.
         * @return The Builder to allow chaining
         */
        @NonNull
        public Builder setSessionActivity(@Nullable PendingIntent pi) {
            mSessionActivity = pi;
            return this;
        }

        /**
         * Set ID of the session. If it's not set, an empty string will be used to create a session.
         * <p>
         * Use this if and only if your app supports multiple playback at the same time and also
         * wants to provide external apps to have finer controls of them.
         *
         * @param id id of the session. Must be unique per package.
         * @throws IllegalArgumentException if id is {@code null}.
         * @return The Builder to allow chaining
         */
        @NonNull
        public Builder setId(@NonNull String id) {
            if (id == null) {
                throw new IllegalArgumentException("id shouldn't be null");
            }
            mId = id;
            return this;
        }

        /**
         * Set callback for the session and its executor.
         *
         * @param executor callback executor
         * @param callback session callback.
         * @return The Builder to allow chaining
         */
        @NonNull
        public Builder setSessionCallback(@NonNull Executor executor,
                @NonNull SessionCallback callback) {
            mCallbackExecutor = executor;
            mCallback = callback;
            return this;
        }

        /**
         * Build {@link MediaSession2}.
         *
         * @return a new session
         * @throws IllegalStateException if the session with the same id is already exists for the
         *      package.
         */
        @NonNull
        public MediaSession2 build() {
            if (mCallbackExecutor == null) {
                mCallbackExecutor = mContext.getMainExecutor();
            }
            if (mCallback == null) {
                mCallback = new SessionCallback() {};
            }
            if (mId == null) {
                mId = "";
            }
            return new MediaSession2(mContext, mId, mSessionActivity, mCallbackExecutor, mCallback);
        }
    }

    /**
     * Information of a controller.
     * <p>
@@ -235,16 +350,16 @@ public class MediaSession2 implements AutoCloseable {
        /**
         * @hide
         */
        public @NonNull RemoteUserInfo getRemoteUserInfo() {
        @NonNull
        public RemoteUserInfo getRemoteUserInfo() {
            return mRemoteUserInfo;
        }

        /**
         * @return package name of the controller. Can be
         *         {@link androidx.media.MediaSessionManager.RemoteUserInfo#LEGACY_CONTROLLER} if
         *         the package name cannot be obtained.
         * @return package name of the controller.
         */
        public @NonNull String getPackageName() {
        @NonNull
        public String getPackageName() {
            return mRemoteUserInfo.getPackageName();
        }

@@ -292,10 +407,6 @@ public class MediaSession2 implements AutoCloseable {
            return "ControllerInfo {pkg=" + mRemoteUserInfo.getPackageName() + ", uid="
                    + mRemoteUserInfo.getUid() + ", allowedCommands=" + mAllowedCommands + "})";
        }

        @Nullable Controller2Link getControllerBinder() {
            return mControllerBinder;
        }
    }

    /**
@@ -316,7 +427,8 @@ public class MediaSession2 implements AutoCloseable {
         * @param controller controller information.
         * @return allowed commands. Can be {@code null} to reject connection.
         */
        @Nullable public Session2CommandGroup onConnect(@NonNull MediaSession2 session,
        @Nullable
        public Session2CommandGroup onConnect(@NonNull MediaSession2 session,
                @NonNull ControllerInfo controller) {
            Session2CommandGroup commands = new Session2CommandGroup.Builder()
                    .addAllPredefinedCommands(Session2Command.COMMAND_VERSION_1)
+3 −2
Original line number Diff line number Diff line
@@ -34,8 +34,9 @@ import java.util.Set;
 * A set of {@link Session2Command} which represents a command group.
 * <p>
 * This API is not generally intended for third party application developers.
 * Use the <a href="{@docRoot}tools/extras/support-library.html">Support Library</a>
 * {@link androidx.media2.SessionCommandGroup} for consistent behavior across all devices.
 * Use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a>
 * <a href="{@docRoot}reference/androidx/media2/package-summary.html">Media2 Library</a>
 * for consistent behavior across all devices.
 * </p>
 * @hide
 */
+3 −2
Original line number Diff line number Diff line
@@ -38,8 +38,9 @@ import java.util.Objects;
 * If it's representing a session service, it may not be ongoing.
 * <p>
 * This API is not generally intended for third party application developers.
 * Use the <a href="{@docRoot}tools/extras/support-library.html">Support Library</a> instead.
 * {@link androidx.media2.SessionToken} for consistent behavior across all devices.
 * Use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a>
 * <a href="{@docRoot}reference/androidx/media2/package-summary.html">Media2 Library</a>
 * for consistent behavior across all devices.
 * <p>
 * This may be passed to apps by the session owner to allow them to create a
 * {@link MediaController2} to communicate with the session.