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

Commit 153187d0 authored by RoboErik's avatar RoboErik Committed by Android (Google) Code Review
Browse files

Merge "Add a class for managing Session priority"

parents 780bee26 a8f95146
Loading
Loading
Loading
Loading
+5 −2
Original line number Diff line number Diff line
@@ -15475,12 +15475,15 @@ package android.media.session {
    method public void disconnect(android.media.session.RouteInfo);
    method public android.media.session.SessionToken getSessionToken();
    method public android.media.session.TransportPerformer getTransportPerformer();
    method public void publish();
    method public boolean isActive();
    method public void release();
    method public void removeCallback(android.media.session.Session.Callback);
    method public void sendEvent(java.lang.String, android.os.Bundle);
    method public void setActive(boolean);
    method public void setFlags(int);
    method public void setRouteOptions(java.util.List<android.media.session.RouteOptions>);
    method public android.media.session.TransportPerformer setTransportPerformerEnabled();
    field public static final int FLAG_HANDLES_MEDIA_BUTTONS = 1; // 0x1
    field public static final int FLAG_HANDLES_TRANSPORT_CONTROLS = 2; // 0x2
  }
  public static abstract class Session.Callback {
+2 −3
Original line number Diff line number Diff line
@@ -31,9 +31,8 @@ import android.os.ResultReceiver;
interface ISession {
    void sendEvent(String event, in Bundle data);
    ISessionController getController();
    void setTransportPerformerEnabled();
    void setFlags(long flags);
    void publish();
    void setFlags(int flags);
    void setActive(boolean active);
    void destroy();

    // These commands are for setting up and communicating with routes
+11 −2
Original line number Diff line number Diff line
@@ -79,6 +79,8 @@ public class MediaSessionLegacyHelper {
        }
        performer.addListener(listener, mHandler);
        holder.mRccListener = listener;
        holder.mFlags |= Session.FLAG_HANDLES_TRANSPORT_CONTROLS;
        holder.mSession.setFlags(holder.mFlags);
        holder.update();
    }

@@ -87,6 +89,8 @@ public class MediaSessionLegacyHelper {
        if (holder != null && holder.mRccListener != null) {
            holder.mSession.getTransportPerformer().removeListener(holder.mRccListener);
            holder.mRccListener = null;
            holder.mFlags &= ~Session.FLAG_HANDLES_TRANSPORT_CONTROLS;
            holder.mSession.setFlags(holder.mFlags);
            holder.update();
        }
    }
@@ -99,6 +103,8 @@ public class MediaSessionLegacyHelper {
            return;
        }
        holder.mMediaButtonListener = new MediaButtonListener(pi, context);
        holder.mFlags |= Session.FLAG_HANDLES_MEDIA_BUTTONS;
        holder.mSession.setFlags(holder.mFlags);
        holder.mSession.getTransportPerformer().addListener(holder.mMediaButtonListener, mHandler);
    }

@@ -106,6 +112,9 @@ public class MediaSessionLegacyHelper {
        SessionHolder holder = getHolder(pi, false);
        if (holder != null && holder.mMediaButtonListener != null) {
            holder.mSession.getTransportPerformer().removeListener(holder.mMediaButtonListener);
            holder.mFlags &= ~Session.FLAG_HANDLES_MEDIA_BUTTONS;
            holder.mSession.setFlags(holder.mFlags);
            holder.mMediaButtonListener = null;
            holder.update();
        }
    }
@@ -114,8 +123,7 @@ public class MediaSessionLegacyHelper {
        SessionHolder holder = mSessions.get(pi);
        if (holder == null && createIfMissing) {
            Session session = mSessionManager.createSession(TAG);
            session.setTransportPerformerEnabled();
            session.publish();
            session.setActive(true);
            holder = new SessionHolder(session, pi);
            mSessions.put(pi, holder);
        }
@@ -194,6 +202,7 @@ public class MediaSessionLegacyHelper {
        public final PendingIntent mPi;
        public MediaButtonListener mMediaButtonListener;
        public TransportPerformer.Listener mRccListener;
        public int mFlags;

        public SessionHolder(Session session, PendingIntent pi) {
            mSession = session;
+44 −47
Original line number Diff line number Diff line
@@ -64,6 +64,19 @@ import java.util.List;
public final class Session {
    private static final String TAG = "Session";

    /**
     * Set this flag on the session to indicate that it can handle media button
     * events.
     */
    public static final int FLAG_HANDLES_MEDIA_BUTTONS = 1 << 0;

    /**
     * Set this flag on the session to indicate that it handles commands through
     * the {@link TransportPerformer}. The performer can be retrieved by calling
     * {@link #getTransportPerformer()}.
     */
    public static final int FLAG_HANDLES_TRANSPORT_CONTROLS = 1 << 1;

    /**
     * System only flag for a session that needs to have priority over all other
     * sessions. This flag ensures this session will receive media button events
@@ -71,7 +84,7 @@ public final class Session {
     *
     * @hide
     */
    public static final long FLAG_EXCLUSIVE_GLOBAL_PRIORITY = 1 << 32;
    public static final int FLAG_EXCLUSIVE_GLOBAL_PRIORITY = 1 << 16;

    private static final int MSG_MEDIA_BUTTON = 1;
    private static final int MSG_COMMAND = 2;
@@ -96,7 +109,7 @@ public final class Session {
    private TransportPerformer mPerformer;
    private Route mRoute;

    private boolean mPublished = false;;
    private boolean mActive = false;;

    /**
     * @hide
@@ -111,6 +124,7 @@ public final class Session {
            throw new RuntimeException("Dead object in MediaSessionController constructor: ", e);
        }
        mSessionToken = new SessionToken(controllerBinder);
        mPerformer = new TransportPerformer(mBinder);
    }

    /**
@@ -158,52 +172,23 @@ public final class Session {
    }

    /**
     * Start using a TransportPerformer with this media session. This must be
     * called before calling publish and cannot be called more than once.
     * Calling this will allow MediaControllers to retrieve a
     * TransportController.
     *
     * @see TransportController
     * @return The TransportPerformer created for this session
     */
    public TransportPerformer setTransportPerformerEnabled() {
        if (mPerformer != null) {
            throw new IllegalStateException("setTransportPerformer can only be called once.");
        }
        if (mPublished) {
            throw new IllegalStateException("setTransportPerformer cannot be called after publish");
        }

        mPerformer = new TransportPerformer(mBinder);
        try {
            mBinder.setTransportPerformerEnabled();
        } catch (RemoteException e) {
            Log.wtf(TAG, "Failure in setTransportPerformerEnabled.", e);
        }
        return mPerformer;
    }

    /**
     * Retrieves the TransportPerformer used by this session. If called before
     * {@link #setTransportPerformerEnabled} null will be returned.
     * Retrieves the {@link TransportPerformer} for this session. To receive
     * commands through the performer you must also set the
     * {@link #FLAG_HANDLES_TRANSPORT_CONTROLS} flag using
     * {@link #setFlags(int)}.
     *
     * @return The TransportPerformer associated with this session or null
     * @return The performer associated with this session.
     */
    public TransportPerformer getTransportPerformer() {
        return mPerformer;
    }

    /**
     * Set any flags for the session. This cannot be called after calling
     * {@link #publish()}.
     * Set any flags for the session.
     *
     * @param flags The flags to set for this session.
     * @hide remove hide once we have non-system flags
     */
    public void setFlags(long flags) {
        if (mPublished) {
            throw new IllegalStateException("setFlags may not be called after publish");
        }
    public void setFlags(int flags) {
        try {
            mBinder.setFlags(flags);
        } catch (RemoteException e) {
@@ -212,20 +197,32 @@ public final class Session {
    }

    /**
     * Call after you have finished setting up the session. This will make it
     * available to listeners and begin pushing updates to MediaControllers.
     * This can only be called once.
     * Set if this session is currently active and ready to receive commands. If
     * set to false your session's controller may not be discoverable. You must
     * set the session to active before it can start receiving media button
     * events or transport commands.
     *
     * @param active Whether this session is active or not.
     */
    public void publish() {
        if (mPublished) {
            throw new RuntimeException("publish() may only be called once.");
    public void setActive(boolean active) {
        if (mActive == active) {
            return;
        }
        try {
            mBinder.publish();
            mBinder.setActive(active);
            mActive = active;
        } catch (RemoteException e) {
            Log.wtf(TAG, "Failure in publish.", e);
            Log.wtf(TAG, "Failure in setActive.", e);
        }
        mPublished = true;
    }

    /**
     * Get the current active state of this session.
     *
     * @return True if the session is active, false otherwise.
     */
    public boolean isActive() {
        return mActive;
    }

    /**
+87 −21
Original line number Diff line number Diff line
@@ -60,6 +60,24 @@ import java.util.UUID;
public class MediaSessionRecord implements IBinder.DeathRecipient {
    private static final String TAG = "MediaSessionRecord";

    /**
     * These are the playback states that count as currently active.
     */
    private static final int[] ACTIVE_STATES = {
            PlaybackState.PLAYSTATE_FAST_FORWARDING,
            PlaybackState.PLAYSTATE_REWINDING,
            PlaybackState.PLAYSTATE_SKIPPING_BACKWARDS,
            PlaybackState.PLAYSTATE_SKIPPING_FORWARDS,
            PlaybackState.PLAYSTATE_BUFFERING,
            PlaybackState.PLAYSTATE_CONNECTING,
            PlaybackState.PLAYSTATE_PLAYING };

    /**
     * The length of time a session will still be considered active after
     * pausing in ms.
     */
    private static final int ACTIVE_BUFFER = 30000;

    private final MessageHandler mHandler;

    private final int mPid;
@@ -75,7 +93,6 @@ public class MediaSessionRecord implements IBinder.DeathRecipient {
            new ArrayList<ISessionControllerCallback>();
    private final ArrayList<RouteRequest> mRequests = new ArrayList<RouteRequest>();

    private boolean mTransportPerformerEnabled = false;
    private RouteInfo mRoute;
    private RouteOptions mRequest;
    private RouteConnectionRecord mConnection;
@@ -88,9 +105,10 @@ public class MediaSessionRecord implements IBinder.DeathRecipient {
    private MediaMetadata mMetadata;
    private PlaybackState mPlaybackState;
    private int mRatingType;
    private long mLastActiveTime;
    // End TransportPerformer fields

    private boolean mIsPublished = false;
    private boolean mIsActive = false;

    public MediaSessionRecord(int pid, String packageName, ISessionCallback cb, String tag,
            MediaSessionService service, Handler handler) {
@@ -158,6 +176,16 @@ public class MediaSessionRecord implements IBinder.DeathRecipient {
        return mFlags;
    }

    /**
     * Check if this session has the specified flag.
     *
     * @param flag The flag to check.
     * @return True if this session has that flag set, false otherwise.
     */
    public boolean hasFlag(int flag) {
        return (mFlags & flag) != 0;
    }

    /**
     * Check if this session has system priorty and should receive media buttons
     * before any other sessions.
@@ -236,12 +264,36 @@ public class MediaSessionRecord implements IBinder.DeathRecipient {
    }

    /**
     * Check if this session has been published by the app yet.
     * Check if this session has been set to active by the app.
     *
     * @return True if it has been published, false otherwise.
     * @return True if the session is active, false otherwise.
     */
    public boolean isPublished() {
        return mIsPublished;
    public boolean isActive() {
        return mIsActive;
    }

    /**
     * Check if the session is currently performing playback. This will also
     * return true if the session was recently paused.
     *
     * @return True if the session is performing playback, false otherwise.
     */
    public boolean isPlaybackActive() {
        int state = mPlaybackState == null ? 0 : mPlaybackState.getState();
        if (isActiveState(state)) {
            return true;
        }
        if (state == mPlaybackState.PLAYSTATE_PAUSED) {
            long inactiveTime = SystemClock.uptimeMillis() - mLastActiveTime;
            if (inactiveTime < ACTIVE_BUFFER) {
                return true;
            }
        }
        return false;
    }

    public boolean isTransportControlEnabled() {
        return hasFlag(Session.FLAG_HANDLES_TRANSPORT_CONTROLS);
    }

    @Override
@@ -255,11 +307,11 @@ public class MediaSessionRecord implements IBinder.DeathRecipient {
        final String indent = prefix + "  ";
        pw.println(indent + "pid=" + mPid);
        pw.println(indent + "info=" + mSessionInfo.toString());
        pw.println(indent + "published=" + mIsPublished);
        pw.println(indent + "transport controls enabled=" + mTransportPerformerEnabled);
        pw.println(indent + "published=" + mIsActive);
        pw.println(indent + "flags=" + mFlags);
        pw.println(indent + "rating type=" + mRatingType);
        pw.println(indent + "controllers: " + mControllerCallbacks.size());
        pw.println(indent + "state=" + mPlaybackState.toString());
        pw.println(indent + "state=" + (mPlaybackState == null ? null : mPlaybackState.toString()));
        pw.println(indent + "metadata:" + getShortMetadataString());
        pw.println(indent + "route requests {");
        int size = mRequests.size();
@@ -272,6 +324,15 @@ public class MediaSessionRecord implements IBinder.DeathRecipient {
        pw.println(indent + "params=" + (mRequest == null ? null : mRequest.toString()));
    }

    private boolean isActiveState(int state) {
        for (int i = 0; i < ACTIVE_STATES.length; i++) {
            if (ACTIVE_STATES[i] == state) {
                return true;
            }
        }
        return false;
    }

    private String getShortMetadataString() {
        int fields = mMetadata == null ? 0 : mMetadata.size();
        String title = mMetadata == null ? null : mMetadata
@@ -414,26 +475,21 @@ public class MediaSessionRecord implements IBinder.DeathRecipient {
        }

        @Override
        public void publish() {
            mIsPublished = true;
            mService.publishSession(MediaSessionRecord.this);
        }
        @Override
        public void setTransportPerformerEnabled() {
            mTransportPerformerEnabled = true;
        public void setActive(boolean active) {
            mIsActive = active;
            mService.updateSession(MediaSessionRecord.this);
            mHandler.post(MessageHandler.MSG_UPDATE_SESSION_STATE);
        }

        @Override
        public void setFlags(long flags) {
        public void setFlags(int flags) {
            if ((flags & Session.FLAG_EXCLUSIVE_GLOBAL_PRIORITY) != 0) {
                int pid = getCallingPid();
                int uid = getCallingUid();
                mService.enforcePhoneStatePermission(pid, uid);
            }
            if (mIsPublished) {
                throw new IllegalStateException("Cannot set flags after publishing session.");
            }
            mFlags = flags;
            mHandler.post(MessageHandler.MSG_UPDATE_SESSION_STATE);
        }

        @Override
@@ -444,7 +500,13 @@ public class MediaSessionRecord implements IBinder.DeathRecipient {

        @Override
        public void setPlaybackState(PlaybackState state) {
            int oldState = mPlaybackState == null ? 0 : mPlaybackState.getState();
            int newState = state == null ? 0 : state.getState();
            if (isActiveState(oldState) && newState == PlaybackState.PLAYSTATE_PAUSED) {
                mLastActiveTime = SystemClock.elapsedRealtime();
            }
            mPlaybackState = state;
            mService.onSessionPlaystateChange(MediaSessionRecord.this, oldState, newState);
            mHandler.post(MessageHandler.MSG_UPDATE_PLAYBACK_STATE);
        }

@@ -708,7 +770,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient {

        @Override
        public boolean isTransportControlEnabled() {
            return mTransportPerformerEnabled;
            return MediaSessionRecord.this.isTransportControlEnabled();
        }

        @Override
@@ -724,6 +786,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient {
        private static final int MSG_SEND_EVENT = 4;
        private static final int MSG_UPDATE_ROUTE_FILTERS = 5;
        private static final int MSG_SEND_COMMAND = 6;
        private static final int MSG_UPDATE_SESSION_STATE = 7;

        public MessageHandler(Looper looper) {
            super(looper);
@@ -748,6 +811,9 @@ public class MediaSessionRecord implements IBinder.DeathRecipient {
                            (Pair<RouteCommand, ResultReceiver>) msg.obj;
                    pushRouteCommand(cmd.first, cmd.second);
                    break;
                case MSG_UPDATE_SESSION_STATE:
                    // TODO add session state
                    break;
            }
        }

Loading