101fe661ae5da3739215d93922412df4b24c859a2RoboErik/*
201fe661ae5da3739215d93922412df4b24c859a2RoboErik * Copyright (C) 2014 The Android Open Source Project
301fe661ae5da3739215d93922412df4b24c859a2RoboErik *
401fe661ae5da3739215d93922412df4b24c859a2RoboErik * Licensed under the Apache License, Version 2.0 (the "License");
501fe661ae5da3739215d93922412df4b24c859a2RoboErik * you may not use this file except in compliance with the License.
601fe661ae5da3739215d93922412df4b24c859a2RoboErik * You may obtain a copy of the License at
701fe661ae5da3739215d93922412df4b24c859a2RoboErik *
801fe661ae5da3739215d93922412df4b24c859a2RoboErik *      http://www.apache.org/licenses/LICENSE-2.0
901fe661ae5da3739215d93922412df4b24c859a2RoboErik *
1001fe661ae5da3739215d93922412df4b24c859a2RoboErik * Unless required by applicable law or agreed to in writing, software
1101fe661ae5da3739215d93922412df4b24c859a2RoboErik * distributed under the License is distributed on an "AS IS" BASIS,
1201fe661ae5da3739215d93922412df4b24c859a2RoboErik * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1301fe661ae5da3739215d93922412df4b24c859a2RoboErik * See the License for the specific language governing permissions and
1401fe661ae5da3739215d93922412df4b24c859a2RoboErik * limitations under the License.
1501fe661ae5da3739215d93922412df4b24c859a2RoboErik */
1601fe661ae5da3739215d93922412df4b24c859a2RoboErik
172f5b057da7d05d5d699a272aa24fd7c97cdda820RoboErikpackage android.media.session;
1801fe661ae5da3739215d93922412df4b24c859a2RoboErik
1976fca4e177e18b591439fdff64b8f5242a5122d0RoboErikimport android.annotation.IntDef;
20c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErikimport android.annotation.NonNull;
21c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErikimport android.annotation.Nullable;
22e34c09daf89fb888fe2638e71758573462d85173RoboErikimport android.app.Activity;
2333983a901176adcc16c820444b667a37e6472243RoboErikimport android.app.PendingIntent;
248b4bffcac996b4083e720310a09d315ca1c4a000RoboErikimport android.content.Context;
2501fe661ae5da3739215d93922412df4b24c859a2RoboErikimport android.content.Intent;
26f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Pealimport android.content.pm.ParceledListSlice;
279db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErikimport android.media.AudioAttributes;
283625bf72cb8bcf3c7f8f8cd8d708d7206824cc62RoboErikimport android.media.MediaDescription;
29c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErikimport android.media.MediaMetadata;
308ae0f34db936a649ddaf9cdd086c224f6514efebRoboErikimport android.media.Rating;
31ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErikimport android.media.VolumeProvider;
32c2045470a343923b0d74ddbd6a6b80fcf6652d66P.Y. Laligandimport android.net.Uri;
3301fe661ae5da3739215d93922412df4b24c859a2RoboErikimport android.os.Bundle;
3401fe661ae5da3739215d93922412df4b24c859a2RoboErikimport android.os.Handler;
3501fe661ae5da3739215d93922412df4b24c859a2RoboErikimport android.os.Looper;
3601fe661ae5da3739215d93922412df4b24c859a2RoboErikimport android.os.Message;
37dba34ba35cd2042d9a8fecfda56e2abe7a680badJeff Brownimport android.os.Parcel;
38dba34ba35cd2042d9a8fecfda56e2abe7a680badJeff Brownimport android.os.Parcelable;
3901fe661ae5da3739215d93922412df4b24c859a2RoboErikimport android.os.RemoteException;
408ae0f34db936a649ddaf9cdd086c224f6514efebRoboErikimport android.os.ResultReceiver;
418b4bffcac996b4083e720310a09d315ca1c4a000RoboErikimport android.os.UserHandle;
42b1e344eaab519aa9bc9db20c891831dfe2bf92abHyundo Moonimport android.media.session.MediaSessionManager.RemoteUserInfo;
433625bf72cb8bcf3c7f8f8cd8d708d7206824cc62RoboErikimport android.service.media.MediaBrowserService;
448ae0f34db936a649ddaf9cdd086c224f6514efebRoboErikimport android.text.TextUtils;
4501fe661ae5da3739215d93922412df4b24c859a2RoboErikimport android.util.Log;
4621c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kimimport android.util.Pair;
47477d1197c3c25c01ace7ea4494437c23720a2eb3RoboErikimport android.view.KeyEvent;
4874d002be26ec9800cb494471f0773493bc83d8f7Jaewan Kimimport android.view.ViewConfiguration;
4901fe661ae5da3739215d93922412df4b24c859a2RoboErik
5076fca4e177e18b591439fdff64b8f5242a5122d0RoboErikimport java.lang.annotation.Retention;
5176fca4e177e18b591439fdff64b8f5242a5122d0RoboErikimport java.lang.annotation.RetentionPolicy;
528ae0f34db936a649ddaf9cdd086c224f6514efebRoboErikimport java.lang.ref.WeakReference;
5307c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErikimport java.util.List;
546edb68bea68d5f324384f3e9e411118eb8dfc781Ajay Panickerimport java.util.Objects;
5501fe661ae5da3739215d93922412df4b24c859a2RoboErik
5601fe661ae5da3739215d93922412df4b24c859a2RoboErik/**
5742ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErik * Allows interaction with media controllers, volume keys, media buttons, and
5842ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErik * transport controls.
5901fe661ae5da3739215d93922412df4b24c859a2RoboErik * <p>
6001fe661ae5da3739215d93922412df4b24c859a2RoboErik * A MediaSession should be created when an app wants to publish media playback
6142ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErik * information or handle media keys. In general an app only needs one session
6242ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErik * for all playback, though multiple sessions can be created to provide finer
6342ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErik * grain controls of media.
6401fe661ae5da3739215d93922412df4b24c859a2RoboErik * <p>
65bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown * Once a session is created the owner of the session may pass its
66bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown * {@link #getSessionToken() session token} to other processes to allow them to
67bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown * create a {@link MediaController} to interact with the session.
6801fe661ae5da3739215d93922412df4b24c859a2RoboErik * <p>
69c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * To receive commands, media keys, and other events a {@link Callback} must be
70477d1197c3c25c01ace7ea4494437c23720a2eb3RoboErik * set with {@link #setCallback(Callback)} and {@link #setActive(boolean)
71477d1197c3c25c01ace7ea4494437c23720a2eb3RoboErik * setActive(true)} must be called.
7201fe661ae5da3739215d93922412df4b24c859a2RoboErik * <p>
7301fe661ae5da3739215d93922412df4b24c859a2RoboErik * When an app is finished performing playback it must call {@link #release()}
7401fe661ae5da3739215d93922412df4b24c859a2RoboErik * to clean up the session and notify any controllers.
7501fe661ae5da3739215d93922412df4b24c859a2RoboErik * <p>
76bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown * MediaSession objects are thread safe.
7701fe661ae5da3739215d93922412df4b24c859a2RoboErik */
7842ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErikpublic final class MediaSession {
79bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown    private static final String TAG = "MediaSession";
8001fe661ae5da3739215d93922412df4b24c859a2RoboErik
81e7880d8eb1903d42e4e2a90c99b58e2240e01e82RoboErik    /**
82a8f951462791a16f47e8c07e552232f31dcefac5RoboErik     * Set this flag on the session to indicate that it can handle media button
83a8f951462791a16f47e8c07e552232f31dcefac5RoboErik     * events.
8492dea33bfebed04533264b06e036d04cc16b9608Jaewan Kim     * @deprecated This flag is no longer used. All media sessions are expected to handle media
8592dea33bfebed04533264b06e036d04cc16b9608Jaewan Kim     * button events now.
86a8f951462791a16f47e8c07e552232f31dcefac5RoboErik     */
8792dea33bfebed04533264b06e036d04cc16b9608Jaewan Kim    @Deprecated
88a8f951462791a16f47e8c07e552232f31dcefac5RoboErik    public static final int FLAG_HANDLES_MEDIA_BUTTONS = 1 << 0;
89a8f951462791a16f47e8c07e552232f31dcefac5RoboErik
90a8f951462791a16f47e8c07e552232f31dcefac5RoboErik    /**
91c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik     * Set this flag on the session to indicate that it handles transport
92477d1197c3c25c01ace7ea4494437c23720a2eb3RoboErik     * control commands through its {@link Callback}.
9392dea33bfebed04533264b06e036d04cc16b9608Jaewan Kim     * @deprecated This flag is no longer used. All media sessions are expected to handle transport
9492dea33bfebed04533264b06e036d04cc16b9608Jaewan Kim     * controls now.
95a8f951462791a16f47e8c07e552232f31dcefac5RoboErik     */
9692dea33bfebed04533264b06e036d04cc16b9608Jaewan Kim    @Deprecated
97a8f951462791a16f47e8c07e552232f31dcefac5RoboErik    public static final int FLAG_HANDLES_TRANSPORT_CONTROLS = 1 << 1;
98a8f951462791a16f47e8c07e552232f31dcefac5RoboErik
99a8f951462791a16f47e8c07e552232f31dcefac5RoboErik    /**
100e7880d8eb1903d42e4e2a90c99b58e2240e01e82RoboErik     * System only flag for a session that needs to have priority over all other
101e7880d8eb1903d42e4e2a90c99b58e2240e01e82RoboErik     * sessions. This flag ensures this session will receive media button events
102e7880d8eb1903d42e4e2a90c99b58e2240e01e82RoboErik     * regardless of the current ordering in the system.
103e7880d8eb1903d42e4e2a90c99b58e2240e01e82RoboErik     *
104e7880d8eb1903d42e4e2a90c99b58e2240e01e82RoboErik     * @hide
105e7880d8eb1903d42e4e2a90c99b58e2240e01e82RoboErik     */
106a8f951462791a16f47e8c07e552232f31dcefac5RoboErik    public static final int FLAG_EXCLUSIVE_GLOBAL_PRIORITY = 1 << 16;
107e7880d8eb1903d42e4e2a90c99b58e2240e01e82RoboErik
108b1e344eaab519aa9bc9db20c891831dfe2bf92abHyundo Moon    /**
109b1e344eaab519aa9bc9db20c891831dfe2bf92abHyundo Moon     * @hide
110b1e344eaab519aa9bc9db20c891831dfe2bf92abHyundo Moon     */
111b1e344eaab519aa9bc9db20c891831dfe2bf92abHyundo Moon    public static final int INVALID_UID = -1;
112b1e344eaab519aa9bc9db20c891831dfe2bf92abHyundo Moon
113b1e344eaab519aa9bc9db20c891831dfe2bf92abHyundo Moon    /**
114b1e344eaab519aa9bc9db20c891831dfe2bf92abHyundo Moon     * @hide
115b1e344eaab519aa9bc9db20c891831dfe2bf92abHyundo Moon     */
116b1e344eaab519aa9bc9db20c891831dfe2bf92abHyundo Moon    public static final int INVALID_PID = -1;
117b1e344eaab519aa9bc9db20c891831dfe2bf92abHyundo Moon
11876fca4e177e18b591439fdff64b8f5242a5122d0RoboErik    /** @hide */
11976fca4e177e18b591439fdff64b8f5242a5122d0RoboErik    @Retention(RetentionPolicy.SOURCE)
12076fca4e177e18b591439fdff64b8f5242a5122d0RoboErik    @IntDef(flag = true, value = {
12176fca4e177e18b591439fdff64b8f5242a5122d0RoboErik            FLAG_HANDLES_MEDIA_BUTTONS,
12276fca4e177e18b591439fdff64b8f5242a5122d0RoboErik            FLAG_HANDLES_TRANSPORT_CONTROLS,
12376fca4e177e18b591439fdff64b8f5242a5122d0RoboErik            FLAG_EXCLUSIVE_GLOBAL_PRIORITY })
12476fca4e177e18b591439fdff64b8f5242a5122d0RoboErik    public @interface SessionFlags { }
12576fca4e177e18b591439fdff64b8f5242a5122d0RoboErik
12601fe661ae5da3739215d93922412df4b24c859a2RoboErik    private final Object mLock = new Object();
127b9c87fb4034a4a61b57150000a937aa95927861cRoboErik    private final int mMaxBitmapSize;
12801fe661ae5da3739215d93922412df4b24c859a2RoboErik
129dba34ba35cd2042d9a8fecfda56e2abe7a680badJeff Brown    private final MediaSession.Token mSessionToken;
130031149cd5f22bd858142633c7a763450f42793f7RoboErik    private final MediaController mController;
13107c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik    private final ISession mBinder;
13201fe661ae5da3739215d93922412df4b24c859a2RoboErik    private final CallbackStub mCbStub;
13301fe661ae5da3739215d93922412df4b24c859a2RoboErik
134bdcb3080b4c061a02a1a0a02f9afe20c1d29cf8aSungsoo Lim    // Do not change the name of mCallback. Support lib accesses this by using reflection.
135bdcb3080b4c061a02a1a0a02f9afe20c1d29cf8aSungsoo Lim    private CallbackMessageHandler mCallback;
136ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik    private VolumeProvider mVolumeProvider;
137477d1197c3c25c01ace7ea4494437c23720a2eb3RoboErik    private PlaybackState mPlaybackState;
1388ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik
139bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown    private boolean mActive = false;
14001fe661ae5da3739215d93922412df4b24c859a2RoboErik
14101fe661ae5da3739215d93922412df4b24c859a2RoboErik    /**
1428b4bffcac996b4083e720310a09d315ca1c4a000RoboErik     * Creates a new session. The session will automatically be registered with
1438b4bffcac996b4083e720310a09d315ca1c4a000RoboErik     * the system but will not be published until {@link #setActive(boolean)
1448b4bffcac996b4083e720310a09d315ca1c4a000RoboErik     * setActive(true)} is called. You must call {@link #release()} when
1458b4bffcac996b4083e720310a09d315ca1c4a000RoboErik     * finished with the session.
1468b4bffcac996b4083e720310a09d315ca1c4a000RoboErik     *
1478b4bffcac996b4083e720310a09d315ca1c4a000RoboErik     * @param context The context to use to create the session.
1488b4bffcac996b4083e720310a09d315ca1c4a000RoboErik     * @param tag A short name for debugging purposes.
1498b4bffcac996b4083e720310a09d315ca1c4a000RoboErik     */
1508b4bffcac996b4083e720310a09d315ca1c4a000RoboErik    public MediaSession(@NonNull Context context, @NonNull String tag) {
1518b4bffcac996b4083e720310a09d315ca1c4a000RoboErik        this(context, tag, UserHandle.myUserId());
1528b4bffcac996b4083e720310a09d315ca1c4a000RoboErik    }
1538b4bffcac996b4083e720310a09d315ca1c4a000RoboErik
1548b4bffcac996b4083e720310a09d315ca1c4a000RoboErik    /**
1558b4bffcac996b4083e720310a09d315ca1c4a000RoboErik     * Creates a new session as the specified user. To create a session as a
1568b4bffcac996b4083e720310a09d315ca1c4a000RoboErik     * user other than your own you must hold the
1578b4bffcac996b4083e720310a09d315ca1c4a000RoboErik     * {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL}
1588b4bffcac996b4083e720310a09d315ca1c4a000RoboErik     * permission.
1598b4bffcac996b4083e720310a09d315ca1c4a000RoboErik     *
1608b4bffcac996b4083e720310a09d315ca1c4a000RoboErik     * @param context The context to use to create the session.
1618b4bffcac996b4083e720310a09d315ca1c4a000RoboErik     * @param tag A short name for debugging purposes.
1628b4bffcac996b4083e720310a09d315ca1c4a000RoboErik     * @param userId The user id to create the session as.
16301fe661ae5da3739215d93922412df4b24c859a2RoboErik     * @hide
16401fe661ae5da3739215d93922412df4b24c859a2RoboErik     */
1658b4bffcac996b4083e720310a09d315ca1c4a000RoboErik    public MediaSession(@NonNull Context context, @NonNull String tag, int userId) {
1668b4bffcac996b4083e720310a09d315ca1c4a000RoboErik        if (context == null) {
1678b4bffcac996b4083e720310a09d315ca1c4a000RoboErik            throw new IllegalArgumentException("context cannot be null.");
1688b4bffcac996b4083e720310a09d315ca1c4a000RoboErik        }
1698b4bffcac996b4083e720310a09d315ca1c4a000RoboErik        if (TextUtils.isEmpty(tag)) {
1708b4bffcac996b4083e720310a09d315ca1c4a000RoboErik            throw new IllegalArgumentException("tag cannot be null or empty");
1718b4bffcac996b4083e720310a09d315ca1c4a000RoboErik        }
172b9c87fb4034a4a61b57150000a937aa95927861cRoboErik        mMaxBitmapSize = context.getResources().getDimensionPixelSize(
173b9c87fb4034a4a61b57150000a937aa95927861cRoboErik                com.android.internal.R.dimen.config_mediaMetadataBitmapMaxSize);
174ca58ddf7c82dd0857de0c3d49d7eb87a842ee4ceRoboErik        mCbStub = new CallbackStub(this);
1758b4bffcac996b4083e720310a09d315ca1c4a000RoboErik        MediaSessionManager manager = (MediaSessionManager) context
1768b4bffcac996b4083e720310a09d315ca1c4a000RoboErik                .getSystemService(Context.MEDIA_SESSION_SERVICE);
17701fe661ae5da3739215d93922412df4b24c859a2RoboErik        try {
1788b4bffcac996b4083e720310a09d315ca1c4a000RoboErik            mBinder = manager.createSession(mCbStub, tag, userId);
1798b4bffcac996b4083e720310a09d315ca1c4a000RoboErik            mSessionToken = new Token(mBinder.getController());
180031149cd5f22bd858142633c7a763450f42793f7RoboErik            mController = new MediaController(context, mSessionToken);
18101fe661ae5da3739215d93922412df4b24c859a2RoboErik        } catch (RemoteException e) {
1828b4bffcac996b4083e720310a09d315ca1c4a000RoboErik            throw new RuntimeException("Remote error creating session.", e);
18301fe661ae5da3739215d93922412df4b24c859a2RoboErik        }
18401fe661ae5da3739215d93922412df4b24c859a2RoboErik    }
18501fe661ae5da3739215d93922412df4b24c859a2RoboErik
18601fe661ae5da3739215d93922412df4b24c859a2RoboErik    /**
187477d1197c3c25c01ace7ea4494437c23720a2eb3RoboErik     * Set the callback to receive updates for the MediaSession. This includes
188477d1197c3c25c01ace7ea4494437c23720a2eb3RoboErik     * media button events and transport controls. The caller's thread will be
189477d1197c3c25c01ace7ea4494437c23720a2eb3RoboErik     * used to post updates.
190477d1197c3c25c01ace7ea4494437c23720a2eb3RoboErik     * <p>
191477d1197c3c25c01ace7ea4494437c23720a2eb3RoboErik     * Set the callback to null to stop receiving updates.
19201fe661ae5da3739215d93922412df4b24c859a2RoboErik     *
19301fe661ae5da3739215d93922412df4b24c859a2RoboErik     * @param callback The callback object
19401fe661ae5da3739215d93922412df4b24c859a2RoboErik     */
195477d1197c3c25c01ace7ea4494437c23720a2eb3RoboErik    public void setCallback(@Nullable Callback callback) {
196477d1197c3c25c01ace7ea4494437c23720a2eb3RoboErik        setCallback(callback, null);
19701fe661ae5da3739215d93922412df4b24c859a2RoboErik    }
19801fe661ae5da3739215d93922412df4b24c859a2RoboErik
19907c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik    /**
200477d1197c3c25c01ace7ea4494437c23720a2eb3RoboErik     * Set the callback to receive updates for the MediaSession. This includes
201477d1197c3c25c01ace7ea4494437c23720a2eb3RoboErik     * media button events and transport controls.
202477d1197c3c25c01ace7ea4494437c23720a2eb3RoboErik     * <p>
203477d1197c3c25c01ace7ea4494437c23720a2eb3RoboErik     * Set the callback to null to stop receiving updates.
20407c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik     *
20507c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik     * @param callback The callback to receive updates on.
20607c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik     * @param handler The handler that events should be posted on.
20707c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik     */
208477d1197c3c25c01ace7ea4494437c23720a2eb3RoboErik    public void setCallback(@Nullable Callback callback, @Nullable Handler handler) {
20901fe661ae5da3739215d93922412df4b24c859a2RoboErik        synchronized (mLock) {
210bdcb3080b4c061a02a1a0a02f9afe20c1d29cf8aSungsoo Lim            if (mCallback != null) {
21162cef488de93888d6f1388b9f8c05a785faafb79Insun Kang                // We're updating the callback, clear the session from the old one.
212bdcb3080b4c061a02a1a0a02f9afe20c1d29cf8aSungsoo Lim                mCallback.mCallback.mSession = null;
213bdcb3080b4c061a02a1a0a02f9afe20c1d29cf8aSungsoo Lim                mCallback.removeCallbacksAndMessages(null);
21462cef488de93888d6f1388b9f8c05a785faafb79Insun Kang            }
2155ea924bcdb7d1a796937a315f59db44179bb4181RoboErik            if (callback == null) {
216bdcb3080b4c061a02a1a0a02f9afe20c1d29cf8aSungsoo Lim                mCallback = null;
2178ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik                return;
21801fe661ae5da3739215d93922412df4b24c859a2RoboErik            }
21901fe661ae5da3739215d93922412df4b24c859a2RoboErik            if (handler == null) {
22001fe661ae5da3739215d93922412df4b24c859a2RoboErik                handler = new Handler();
22101fe661ae5da3739215d93922412df4b24c859a2RoboErik            }
2225ea924bcdb7d1a796937a315f59db44179bb4181RoboErik            callback.mSession = this;
223c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik            CallbackMessageHandler msgHandler = new CallbackMessageHandler(handler.getLooper(),
224c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik                    callback);
225bdcb3080b4c061a02a1a0a02f9afe20c1d29cf8aSungsoo Lim            mCallback = msgHandler;
2268ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        }
2278ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik    }
2288ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik
2298ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik    /**
23033983a901176adcc16c820444b667a37e6472243RoboErik     * Set an intent for launching UI for this Session. This can be used as a
231e34c09daf89fb888fe2638e71758573462d85173RoboErik     * quick link to an ongoing media screen. The intent should be for an
232e34c09daf89fb888fe2638e71758573462d85173RoboErik     * activity that may be started using {@link Activity#startActivity(Intent)}.
23333983a901176adcc16c820444b667a37e6472243RoboErik     *
23433983a901176adcc16c820444b667a37e6472243RoboErik     * @param pi The intent to launch to show UI for this Session.
23533983a901176adcc16c820444b667a37e6472243RoboErik     */
236d2b8c947ddfc6349a3ae6c3968b422b9cf50d7edRoboErik    public void setSessionActivity(@Nullable PendingIntent pi) {
237e34c09daf89fb888fe2638e71758573462d85173RoboErik        try {
238e34c09daf89fb888fe2638e71758573462d85173RoboErik            mBinder.setLaunchPendingIntent(pi);
239e34c09daf89fb888fe2638e71758573462d85173RoboErik        } catch (RemoteException e) {
240e34c09daf89fb888fe2638e71758573462d85173RoboErik            Log.wtf(TAG, "Failure in setLaunchPendingIntent.", e);
241e34c09daf89fb888fe2638e71758573462d85173RoboErik        }
24233983a901176adcc16c820444b667a37e6472243RoboErik    }
24333983a901176adcc16c820444b667a37e6472243RoboErik
24433983a901176adcc16c820444b667a37e6472243RoboErik    /**
245b214efbb9170a9f6a4991684a63ca59680074cc7RoboErik     * Set a pending intent for your media button receiver to allow restarting
246b214efbb9170a9f6a4991684a63ca59680074cc7RoboErik     * playback after the session has been stopped. If your app is started in
247b214efbb9170a9f6a4991684a63ca59680074cc7RoboErik     * this way an {@link Intent#ACTION_MEDIA_BUTTON} intent will be sent via
248b214efbb9170a9f6a4991684a63ca59680074cc7RoboErik     * the pending intent.
2496f0e4ddd66fcdcc13944d8970d0b560e2626508bRoboErik     *
250b214efbb9170a9f6a4991684a63ca59680074cc7RoboErik     * @param mbr The {@link PendingIntent} to send the media button event to.
2516f0e4ddd66fcdcc13944d8970d0b560e2626508bRoboErik     */
252b214efbb9170a9f6a4991684a63ca59680074cc7RoboErik    public void setMediaButtonReceiver(@Nullable PendingIntent mbr) {
2536f0e4ddd66fcdcc13944d8970d0b560e2626508bRoboErik        try {
2546f0e4ddd66fcdcc13944d8970d0b560e2626508bRoboErik            mBinder.setMediaButtonReceiver(mbr);
2556f0e4ddd66fcdcc13944d8970d0b560e2626508bRoboErik        } catch (RemoteException e) {
2566f0e4ddd66fcdcc13944d8970d0b560e2626508bRoboErik            Log.wtf(TAG, "Failure in setMediaButtonReceiver.", e);
2576f0e4ddd66fcdcc13944d8970d0b560e2626508bRoboErik        }
2586f0e4ddd66fcdcc13944d8970d0b560e2626508bRoboErik    }
2596f0e4ddd66fcdcc13944d8970d0b560e2626508bRoboErik
2606f0e4ddd66fcdcc13944d8970d0b560e2626508bRoboErik    /**
261a8f951462791a16f47e8c07e552232f31dcefac5RoboErik     * Set any flags for the session.
262e7880d8eb1903d42e4e2a90c99b58e2240e01e82RoboErik     *
263e7880d8eb1903d42e4e2a90c99b58e2240e01e82RoboErik     * @param flags The flags to set for this session.
264e7880d8eb1903d42e4e2a90c99b58e2240e01e82RoboErik     */
26576fca4e177e18b591439fdff64b8f5242a5122d0RoboErik    public void setFlags(@SessionFlags int flags) {
266e7880d8eb1903d42e4e2a90c99b58e2240e01e82RoboErik        try {
267e7880d8eb1903d42e4e2a90c99b58e2240e01e82RoboErik            mBinder.setFlags(flags);
268e7880d8eb1903d42e4e2a90c99b58e2240e01e82RoboErik        } catch (RemoteException e) {
269e7880d8eb1903d42e4e2a90c99b58e2240e01e82RoboErik            Log.wtf(TAG, "Failure in setFlags.", e);
270e7880d8eb1903d42e4e2a90c99b58e2240e01e82RoboErik        }
271e7880d8eb1903d42e4e2a90c99b58e2240e01e82RoboErik    }
272e7880d8eb1903d42e4e2a90c99b58e2240e01e82RoboErik
273e7880d8eb1903d42e4e2a90c99b58e2240e01e82RoboErik    /**
2749db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik     * Set the attributes for this session's audio. This will affect the
2759db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik     * system's volume handling for this session. If
2769db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik     * {@link #setPlaybackToRemote} was previously called it will stop receiving
2779db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik     * volume commands and the system will begin sending volume changes to the
2789db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik     * appropriate stream.
27933983a901176adcc16c820444b667a37e6472243RoboErik     * <p>
2809db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik     * By default sessions use attributes for media.
28133983a901176adcc16c820444b667a37e6472243RoboErik     *
2829db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik     * @param attributes The {@link AudioAttributes} for this session's audio.
28333983a901176adcc16c820444b667a37e6472243RoboErik     */
2849db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik    public void setPlaybackToLocal(AudioAttributes attributes) {
2859db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik        if (attributes == null) {
2869db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik            throw new IllegalArgumentException("Attributes cannot be null for local playback.");
2879db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik        }
288b69ffd4dc2c8fa85e0064151141ebeee90de471eRoboErik        try {
2899db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik            mBinder.setPlaybackToLocal(attributes);
290b69ffd4dc2c8fa85e0064151141ebeee90de471eRoboErik        } catch (RemoteException e) {
291b69ffd4dc2c8fa85e0064151141ebeee90de471eRoboErik            Log.wtf(TAG, "Failure in setPlaybackToLocal.", e);
292b69ffd4dc2c8fa85e0064151141ebeee90de471eRoboErik        }
29333983a901176adcc16c820444b667a37e6472243RoboErik    }
29433983a901176adcc16c820444b667a37e6472243RoboErik
29533983a901176adcc16c820444b667a37e6472243RoboErik    /**
29633983a901176adcc16c820444b667a37e6472243RoboErik     * Configure this session to use remote volume handling. This must be called
29733983a901176adcc16c820444b667a37e6472243RoboErik     * to receive volume button events, otherwise the system will adjust the
2989db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik     * appropriate stream volume for this session. If
2999db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik     * {@link #setPlaybackToLocal} was previously called the system will stop
3009db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik     * handling volume changes for this session and pass them to the volume
3019db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik     * provider instead.
30233983a901176adcc16c820444b667a37e6472243RoboErik     *
30333983a901176adcc16c820444b667a37e6472243RoboErik     * @param volumeProvider The provider that will handle volume changes. May
30433983a901176adcc16c820444b667a37e6472243RoboErik     *            not be null.
30533983a901176adcc16c820444b667a37e6472243RoboErik     */
306bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown    public void setPlaybackToRemote(@NonNull VolumeProvider volumeProvider) {
30733983a901176adcc16c820444b667a37e6472243RoboErik        if (volumeProvider == null) {
30833983a901176adcc16c820444b667a37e6472243RoboErik            throw new IllegalArgumentException("volumeProvider may not be null!");
30933983a901176adcc16c820444b667a37e6472243RoboErik        }
310563acea6665c45902bbc46db1a22c036344a818bRoboErik        synchronized (mLock) {
311563acea6665c45902bbc46db1a22c036344a818bRoboErik            mVolumeProvider = volumeProvider;
312563acea6665c45902bbc46db1a22c036344a818bRoboErik        }
313bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown        volumeProvider.setCallback(new VolumeProvider.Callback() {
314bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown            @Override
315bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown            public void onVolumeChanged(VolumeProvider volumeProvider) {
316bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown                notifyRemoteVolumeChanged(volumeProvider);
317bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown            }
318bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown        });
319b69ffd4dc2c8fa85e0064151141ebeee90de471eRoboErik
320b69ffd4dc2c8fa85e0064151141ebeee90de471eRoboErik        try {
3219db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik            mBinder.setPlaybackToRemote(volumeProvider.getVolumeControl(),
322b69ffd4dc2c8fa85e0064151141ebeee90de471eRoboErik                    volumeProvider.getMaxVolume());
3230d0f67f5ee5f939a1b611bc4583212707afd9beeRoboErik            mBinder.setCurrentVolume(volumeProvider.getCurrentVolume());
324b69ffd4dc2c8fa85e0064151141ebeee90de471eRoboErik        } catch (RemoteException e) {
325b69ffd4dc2c8fa85e0064151141ebeee90de471eRoboErik            Log.wtf(TAG, "Failure in setPlaybackToRemote.", e);
326b69ffd4dc2c8fa85e0064151141ebeee90de471eRoboErik        }
32733983a901176adcc16c820444b667a37e6472243RoboErik    }
32833983a901176adcc16c820444b667a37e6472243RoboErik
32933983a901176adcc16c820444b667a37e6472243RoboErik    /**
330a8f951462791a16f47e8c07e552232f31dcefac5RoboErik     * Set if this session is currently active and ready to receive commands. If
331a8f951462791a16f47e8c07e552232f31dcefac5RoboErik     * set to false your session's controller may not be discoverable. You must
332a8f951462791a16f47e8c07e552232f31dcefac5RoboErik     * set the session to active before it can start receiving media button
333a8f951462791a16f47e8c07e552232f31dcefac5RoboErik     * events or transport commands.
334a8f951462791a16f47e8c07e552232f31dcefac5RoboErik     *
335a8f951462791a16f47e8c07e552232f31dcefac5RoboErik     * @param active Whether this session is active or not.
3368ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik     */
337a8f951462791a16f47e8c07e552232f31dcefac5RoboErik    public void setActive(boolean active) {
338a8f951462791a16f47e8c07e552232f31dcefac5RoboErik        if (mActive == active) {
339a8f951462791a16f47e8c07e552232f31dcefac5RoboErik            return;
3408ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        }
3418ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        try {
342a8f951462791a16f47e8c07e552232f31dcefac5RoboErik            mBinder.setActive(active);
343a8f951462791a16f47e8c07e552232f31dcefac5RoboErik            mActive = active;
3448ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        } catch (RemoteException e) {
345a8f951462791a16f47e8c07e552232f31dcefac5RoboErik            Log.wtf(TAG, "Failure in setActive.", e);
3468ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        }
347a8f951462791a16f47e8c07e552232f31dcefac5RoboErik    }
348a8f951462791a16f47e8c07e552232f31dcefac5RoboErik
349a8f951462791a16f47e8c07e552232f31dcefac5RoboErik    /**
350a8f951462791a16f47e8c07e552232f31dcefac5RoboErik     * Get the current active state of this session.
351a8f951462791a16f47e8c07e552232f31dcefac5RoboErik     *
352a8f951462791a16f47e8c07e552232f31dcefac5RoboErik     * @return True if the session is active, false otherwise.
353a8f951462791a16f47e8c07e552232f31dcefac5RoboErik     */
354a8f951462791a16f47e8c07e552232f31dcefac5RoboErik    public boolean isActive() {
355a8f951462791a16f47e8c07e552232f31dcefac5RoboErik        return mActive;
3568ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik    }
3578ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik
3588ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik    /**
3598ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik     * Send a proprietary event to all MediaControllers listening to this
3608ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik     * Session. It's up to the Controller/Session owner to determine the meaning
3618ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik     * of any events.
36201fe661ae5da3739215d93922412df4b24c859a2RoboErik     *
3638ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik     * @param event The name of the event to send
3648ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik     * @param extras Any extras included with the event
36501fe661ae5da3739215d93922412df4b24c859a2RoboErik     */
366bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown    public void sendSessionEvent(@NonNull String event, @Nullable Bundle extras) {
3678ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        if (TextUtils.isEmpty(event)) {
3688ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik            throw new IllegalArgumentException("event cannot be null or empty");
3698ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        }
37001fe661ae5da3739215d93922412df4b24c859a2RoboErik        try {
3718ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik            mBinder.sendEvent(event, extras);
37201fe661ae5da3739215d93922412df4b24c859a2RoboErik        } catch (RemoteException e) {
3738ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik            Log.wtf(TAG, "Error sending event", e);
37401fe661ae5da3739215d93922412df4b24c859a2RoboErik        }
37501fe661ae5da3739215d93922412df4b24c859a2RoboErik    }
37601fe661ae5da3739215d93922412df4b24c859a2RoboErik
37701fe661ae5da3739215d93922412df4b24c859a2RoboErik    /**
37801fe661ae5da3739215d93922412df4b24c859a2RoboErik     * This must be called when an app has finished performing playback. If
37901fe661ae5da3739215d93922412df4b24c859a2RoboErik     * playback is expected to start again shortly the session can be left open,
38001fe661ae5da3739215d93922412df4b24c859a2RoboErik     * but it must be released if your activity or service is being destroyed.
38101fe661ae5da3739215d93922412df4b24c859a2RoboErik     */
38201fe661ae5da3739215d93922412df4b24c859a2RoboErik    public void release() {
38301fe661ae5da3739215d93922412df4b24c859a2RoboErik        try {
38401fe661ae5da3739215d93922412df4b24c859a2RoboErik            mBinder.destroy();
38501fe661ae5da3739215d93922412df4b24c859a2RoboErik        } catch (RemoteException e) {
3868ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik            Log.wtf(TAG, "Error releasing session: ", e);
38701fe661ae5da3739215d93922412df4b24c859a2RoboErik        }
38801fe661ae5da3739215d93922412df4b24c859a2RoboErik    }
38901fe661ae5da3739215d93922412df4b24c859a2RoboErik
39001fe661ae5da3739215d93922412df4b24c859a2RoboErik    /**
39101fe661ae5da3739215d93922412df4b24c859a2RoboErik     * Retrieve a token object that can be used by apps to create a
39242ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErik     * {@link MediaController} for interacting with this session. The owner of
39301fe661ae5da3739215d93922412df4b24c859a2RoboErik     * the session is responsible for deciding how to distribute these tokens.
39401fe661ae5da3739215d93922412df4b24c859a2RoboErik     *
39501fe661ae5da3739215d93922412df4b24c859a2RoboErik     * @return A token that can be used to create a MediaController for this
39601fe661ae5da3739215d93922412df4b24c859a2RoboErik     *         session
39701fe661ae5da3739215d93922412df4b24c859a2RoboErik     */
398dba34ba35cd2042d9a8fecfda56e2abe7a680badJeff Brown    public @NonNull Token getSessionToken() {
39901fe661ae5da3739215d93922412df4b24c859a2RoboErik        return mSessionToken;
40001fe661ae5da3739215d93922412df4b24c859a2RoboErik    }
40101fe661ae5da3739215d93922412df4b24c859a2RoboErik
40207c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik    /**
403031149cd5f22bd858142633c7a763450f42793f7RoboErik     * Get a controller for this session. This is a convenience method to avoid
404031149cd5f22bd858142633c7a763450f42793f7RoboErik     * having to cache your own controller in process.
405031149cd5f22bd858142633c7a763450f42793f7RoboErik     *
406031149cd5f22bd858142633c7a763450f42793f7RoboErik     * @return A controller for this session.
407031149cd5f22bd858142633c7a763450f42793f7RoboErik     */
408031149cd5f22bd858142633c7a763450f42793f7RoboErik    public @NonNull MediaController getController() {
409031149cd5f22bd858142633c7a763450f42793f7RoboErik        return mController;
410031149cd5f22bd858142633c7a763450f42793f7RoboErik    }
411031149cd5f22bd858142633c7a763450f42793f7RoboErik
412031149cd5f22bd858142633c7a763450f42793f7RoboErik    /**
413c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik     * Update the current playback state.
414c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik     *
415c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik     * @param state The current state of playback
416c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik     */
417bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown    public void setPlaybackState(@Nullable PlaybackState state) {
418477d1197c3c25c01ace7ea4494437c23720a2eb3RoboErik        mPlaybackState = state;
419c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik        try {
420c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik            mBinder.setPlaybackState(state);
421c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik        } catch (RemoteException e) {
422c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik            Log.wtf(TAG, "Dead object in setPlaybackState.", e);
423c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik        }
424c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik    }
425c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik
426c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik    /**
427c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik     * Update the current metadata. New metadata can be created using
428762194c22da77d9369bce61e972d6b3fc43164c0Jaewan Kim     * {@link android.media.MediaMetadata.Builder}. This operation may take time proportional to
429762194c22da77d9369bce61e972d6b3fc43164c0Jaewan Kim     * the size of the bitmap to replace large bitmaps with a scaled down copy.
430c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik     *
431c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik     * @param metadata The new metadata
432762194c22da77d9369bce61e972d6b3fc43164c0Jaewan Kim     * @see android.media.MediaMetadata.Builder#putBitmap
433c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik     */
434bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown    public void setMetadata(@Nullable MediaMetadata metadata) {
435762194c22da77d9369bce61e972d6b3fc43164c0Jaewan Kim        if (metadata != null) {
436f32bd3c5cd8bd2c00f52ea32d7481c30e29d2accMichael Wright            metadata = (new MediaMetadata.Builder(metadata, mMaxBitmapSize)).build();
437f32bd3c5cd8bd2c00f52ea32d7481c30e29d2accMichael Wright        }
438c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik        try {
439c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik            mBinder.setMetadata(metadata);
440c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik        } catch (RemoteException e) {
441c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik            Log.wtf(TAG, "Dead object in setPlaybackState.", e);
442c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik        }
443c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik    }
444c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik
4455d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik    /**
446a66c40bf6e0fb79ead6d8a9fc29c5671fa7b1206RoboErik     * Update the list of items in the play queue. It is an ordered list and
447a66c40bf6e0fb79ead6d8a9fc29c5671fa7b1206RoboErik     * should contain the current item, and previous or upcoming items if they
448a66c40bf6e0fb79ead6d8a9fc29c5671fa7b1206RoboErik     * exist. Specify null if there is no current play queue.
449f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal     * <p>
450a66c40bf6e0fb79ead6d8a9fc29c5671fa7b1206RoboErik     * The queue should be of reasonable size. If the play queue is unbounded
451a66c40bf6e0fb79ead6d8a9fc29c5671fa7b1206RoboErik     * within your app, it is better to send a reasonable amount in a sliding
452a66c40bf6e0fb79ead6d8a9fc29c5671fa7b1206RoboErik     * window instead.
453f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal     *
454a66c40bf6e0fb79ead6d8a9fc29c5671fa7b1206RoboErik     * @param queue A list of items in the play queue.
455f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal     */
4563625bf72cb8bcf3c7f8f8cd8d708d7206824cc62RoboErik    public void setQueue(@Nullable List<QueueItem> queue) {
457f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal        try {
45803fce072cac092923e10a6b5f09fcde333375f9eRoboErik            mBinder.setQueue(queue == null ? null : new ParceledListSlice<QueueItem>(queue));
459f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal        } catch (RemoteException e) {
460f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal            Log.wtf("Dead object in setQueue.", e);
461f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal        }
462f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal    }
463f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal
464f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal    /**
465f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal     * Set the title of the play queue. The UI should display this title along
466f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal     * with the play queue itself.
467f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal     * e.g. "Play Queue", "Now Playing", or an album name.
468f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal     *
469f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal     * @param title The title of the play queue.
470f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal     */
471f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal    public void setQueueTitle(@Nullable CharSequence title) {
472f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal        try {
473f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal            mBinder.setQueueTitle(title);
474f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal        } catch (RemoteException e) {
475f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal            Log.wtf("Dead object in setQueueTitle.", e);
476f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal        }
477f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal    }
478f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal
479f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal    /**
480566c1ed18f429a7a64aeac01baa0af150fcd1eb4RoboErik     * Set the style of rating used by this session. Apps trying to set the
481566c1ed18f429a7a64aeac01baa0af150fcd1eb4RoboErik     * rating should use this style. Must be one of the following:
482566c1ed18f429a7a64aeac01baa0af150fcd1eb4RoboErik     * <ul>
483566c1ed18f429a7a64aeac01baa0af150fcd1eb4RoboErik     * <li>{@link Rating#RATING_NONE}</li>
484566c1ed18f429a7a64aeac01baa0af150fcd1eb4RoboErik     * <li>{@link Rating#RATING_3_STARS}</li>
485566c1ed18f429a7a64aeac01baa0af150fcd1eb4RoboErik     * <li>{@link Rating#RATING_4_STARS}</li>
486566c1ed18f429a7a64aeac01baa0af150fcd1eb4RoboErik     * <li>{@link Rating#RATING_5_STARS}</li>
487566c1ed18f429a7a64aeac01baa0af150fcd1eb4RoboErik     * <li>{@link Rating#RATING_HEART}</li>
488566c1ed18f429a7a64aeac01baa0af150fcd1eb4RoboErik     * <li>{@link Rating#RATING_PERCENTAGE}</li>
489566c1ed18f429a7a64aeac01baa0af150fcd1eb4RoboErik     * <li>{@link Rating#RATING_THUMB_UP_DOWN}</li>
490566c1ed18f429a7a64aeac01baa0af150fcd1eb4RoboErik     * </ul>
491566c1ed18f429a7a64aeac01baa0af150fcd1eb4RoboErik     */
4927c090d54e2c0eb5309d3f7dc131e137d9c986793Insun Kang    public void setRatingType(@Rating.Style int type) {
493566c1ed18f429a7a64aeac01baa0af150fcd1eb4RoboErik        try {
494566c1ed18f429a7a64aeac01baa0af150fcd1eb4RoboErik            mBinder.setRatingType(type);
495566c1ed18f429a7a64aeac01baa0af150fcd1eb4RoboErik        } catch (RemoteException e) {
496566c1ed18f429a7a64aeac01baa0af150fcd1eb4RoboErik            Log.e(TAG, "Error in setRatingType.", e);
497566c1ed18f429a7a64aeac01baa0af150fcd1eb4RoboErik        }
498566c1ed18f429a7a64aeac01baa0af150fcd1eb4RoboErik    }
499566c1ed18f429a7a64aeac01baa0af150fcd1eb4RoboErik
500566c1ed18f429a7a64aeac01baa0af150fcd1eb4RoboErik    /**
501f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal     * Set some extras that can be associated with the {@link MediaSession}. No assumptions should
502f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal     * be made as to how a {@link MediaController} will handle these extras.
503f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal     * Keys should be fully qualified (e.g. com.example.MY_EXTRA) to avoid conflicts.
504f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal     *
505f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal     * @param extras The extras associated with the {@link MediaSession}.
506f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal     */
507f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal    public void setExtras(@Nullable Bundle extras) {
508f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal        try {
509f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal            mBinder.setExtras(extras);
510f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal        } catch (RemoteException e) {
511f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal            Log.wtf("Dead object in setExtras.", e);
512f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal        }
513f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal    }
514f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal
515f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal    /**
516b1e344eaab519aa9bc9db20c891831dfe2bf92abHyundo Moon     * Gets the controller information who sent the current request.
517b1e344eaab519aa9bc9db20c891831dfe2bf92abHyundo Moon     * <p>
518b1e344eaab519aa9bc9db20c891831dfe2bf92abHyundo Moon     * Note: This is only valid while in a request callback, such as {@link Callback#onPlay}.
519b1e344eaab519aa9bc9db20c891831dfe2bf92abHyundo Moon     *
520b1e344eaab519aa9bc9db20c891831dfe2bf92abHyundo Moon     * @throws IllegalStateException If this method is called outside of {@link Callback} methods.
521b1e344eaab519aa9bc9db20c891831dfe2bf92abHyundo Moon     * @see MediaSessionManager#isTrustedForMediaControl(RemoteUserInfo)
522b1e344eaab519aa9bc9db20c891831dfe2bf92abHyundo Moon     */
523b1e344eaab519aa9bc9db20c891831dfe2bf92abHyundo Moon    public final @NonNull RemoteUserInfo getCurrentControllerInfo() {
52421c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim        if (mCallback == null || mCallback.mCurrentControllerInfo == null) {
525b1e344eaab519aa9bc9db20c891831dfe2bf92abHyundo Moon            throw new IllegalStateException(
526b1e344eaab519aa9bc9db20c891831dfe2bf92abHyundo Moon                    "This should be called inside of MediaSession.Callback methods");
527b1e344eaab519aa9bc9db20c891831dfe2bf92abHyundo Moon        }
52821c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim        return mCallback.mCurrentControllerInfo;
529b1e344eaab519aa9bc9db20c891831dfe2bf92abHyundo Moon    }
530b1e344eaab519aa9bc9db20c891831dfe2bf92abHyundo Moon
531b1e344eaab519aa9bc9db20c891831dfe2bf92abHyundo Moon    /**
532ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik     * Notify the system that the remote volume changed.
5335d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik     *
5345d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik     * @param provider The provider that is handling volume changes.
5355d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik     * @hide
5365d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik     */
537ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik    public void notifyRemoteVolumeChanged(VolumeProvider provider) {
538563acea6665c45902bbc46db1a22c036344a818bRoboErik        synchronized (mLock) {
539563acea6665c45902bbc46db1a22c036344a818bRoboErik            if (provider == null || provider != mVolumeProvider) {
540563acea6665c45902bbc46db1a22c036344a818bRoboErik                Log.w(TAG, "Received update from stale volume provider");
541563acea6665c45902bbc46db1a22c036344a818bRoboErik                return;
542563acea6665c45902bbc46db1a22c036344a818bRoboErik            }
5435d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik        }
5445d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik        try {
5450d0f67f5ee5f939a1b611bc4583212707afd9beeRoboErik            mBinder.setCurrentVolume(provider.getCurrentVolume());
5465d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik        } catch (RemoteException e) {
5475d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik            Log.e(TAG, "Error in notifyVolumeChanged", e);
5485d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik        }
5495d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik    }
5505d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik
5511ea56832178b40ce5a54ee77e6a01108496dc6e9Donghyun Cho    /**
5521ea56832178b40ce5a54ee77e6a01108496dc6e9Donghyun Cho     * Returns the name of the package that sent the last media button, transport control, or
5531ea56832178b40ce5a54ee77e6a01108496dc6e9Donghyun Cho     * command from controllers and the system. This is only valid while in a request callback, such
5541ea56832178b40ce5a54ee77e6a01108496dc6e9Donghyun Cho     * as {@link Callback#onPlay}.
5551ea56832178b40ce5a54ee77e6a01108496dc6e9Donghyun Cho     *
5561ea56832178b40ce5a54ee77e6a01108496dc6e9Donghyun Cho     * @hide
5571ea56832178b40ce5a54ee77e6a01108496dc6e9Donghyun Cho     */
5581ea56832178b40ce5a54ee77e6a01108496dc6e9Donghyun Cho    public String getCallingPackage() {
55921c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim        if (mCallback != null && mCallback.mCurrentControllerInfo != null) {
56021c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim            return mCallback.mCurrentControllerInfo.getPackageName();
5611ea56832178b40ce5a54ee77e6a01108496dc6e9Donghyun Cho        }
5621ea56832178b40ce5a54ee77e6a01108496dc6e9Donghyun Cho        return null;
5631ea56832178b40ce5a54ee77e6a01108496dc6e9Donghyun Cho    }
5641ea56832178b40ce5a54ee77e6a01108496dc6e9Donghyun Cho
56521c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim    private void dispatchPrepare(RemoteUserInfo caller) {
56621c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim        postToCallback(caller, CallbackMessageHandler.MSG_PREPARE, null, null);
56722188f118754c3b31c13d2f94daf718f111d92afDonghyun Cho    }
56822188f118754c3b31c13d2f94daf718f111d92afDonghyun Cho
56921c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim    private void dispatchPrepareFromMediaId(RemoteUserInfo caller, String mediaId, Bundle extras) {
57021c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim        postToCallback(caller, CallbackMessageHandler.MSG_PREPARE_MEDIA_ID, mediaId, extras);
57122188f118754c3b31c13d2f94daf718f111d92afDonghyun Cho    }
57222188f118754c3b31c13d2f94daf718f111d92afDonghyun Cho
57321c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim    private void dispatchPrepareFromSearch(RemoteUserInfo caller, String query, Bundle extras) {
57421c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim        postToCallback(caller, CallbackMessageHandler.MSG_PREPARE_SEARCH, query, extras);
57522188f118754c3b31c13d2f94daf718f111d92afDonghyun Cho    }
57622188f118754c3b31c13d2f94daf718f111d92afDonghyun Cho
57721c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim    private void dispatchPrepareFromUri(RemoteUserInfo caller, Uri uri, Bundle extras) {
57821c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim        postToCallback(caller, CallbackMessageHandler.MSG_PREPARE_URI, uri, extras);
57922188f118754c3b31c13d2f94daf718f111d92afDonghyun Cho    }
58022188f118754c3b31c13d2f94daf718f111d92afDonghyun Cho
58121c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim    private void dispatchPlay(RemoteUserInfo caller) {
58221c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim        postToCallback(caller, CallbackMessageHandler.MSG_PLAY, null, null);
583c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik    }
584c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik
58521c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim    private void dispatchPlayFromMediaId(RemoteUserInfo caller, String mediaId, Bundle extras) {
58621c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim        postToCallback(caller, CallbackMessageHandler.MSG_PLAY_MEDIA_ID, mediaId, extras);
587f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal    }
588f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal
58921c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim    private void dispatchPlayFromSearch(RemoteUserInfo caller, String query, Bundle extras) {
59021c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim        postToCallback(caller, CallbackMessageHandler.MSG_PLAY_SEARCH, query, extras);
591f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal    }
592f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal
59321c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim    private void dispatchPlayFromUri(RemoteUserInfo caller, Uri uri, Bundle extras) {
59421c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim        postToCallback(caller, CallbackMessageHandler.MSG_PLAY_URI, uri, extras);
595c2045470a343923b0d74ddbd6a6b80fcf6652d66P.Y. Laligand    }
596c2045470a343923b0d74ddbd6a6b80fcf6652d66P.Y. Laligand
59721c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim    private void dispatchSkipToItem(RemoteUserInfo caller, long id) {
59821c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim        postToCallback(caller, CallbackMessageHandler.MSG_SKIP_TO_ITEM, id, null);
599f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal    }
600f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal
60121c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim    private void dispatchPause(RemoteUserInfo caller) {
60221c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim        postToCallback(caller, CallbackMessageHandler.MSG_PAUSE, null, null);
603c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik    }
604c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik
60521c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim    private void dispatchStop(RemoteUserInfo caller) {
60621c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim        postToCallback(caller, CallbackMessageHandler.MSG_STOP, null, null);
607c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik    }
608c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik
60921c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim    private void dispatchNext(RemoteUserInfo caller) {
61021c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim        postToCallback(caller, CallbackMessageHandler.MSG_NEXT, null, null);
611c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik    }
612c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik
61321c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim    private void dispatchPrevious(RemoteUserInfo caller) {
61421c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim        postToCallback(caller, CallbackMessageHandler.MSG_PREVIOUS, null, null);
615c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik    }
616c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik
61721c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim    private void dispatchFastForward(RemoteUserInfo caller) {
61821c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim        postToCallback(caller, CallbackMessageHandler.MSG_FAST_FORWARD, null, null);
619c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik    }
620c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik
62121c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim    private void dispatchRewind(RemoteUserInfo caller) {
62221c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim        postToCallback(caller, CallbackMessageHandler.MSG_REWIND, null, null);
623c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik    }
624c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik
62521c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim    private void dispatchSeekTo(RemoteUserInfo caller, long pos) {
62621c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim        postToCallback(caller, CallbackMessageHandler.MSG_SEEK_TO, pos, null);
627c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik    }
628c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik
62921c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim    private void dispatchRate(RemoteUserInfo caller, Rating rating) {
63021c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim        postToCallback(caller, CallbackMessageHandler.MSG_RATE, rating, null);
631c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik    }
632c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik
63321c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim    private void dispatchCustomAction(RemoteUserInfo caller, String action, Bundle args) {
63421c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim        postToCallback(caller, CallbackMessageHandler.MSG_CUSTOM_ACTION, action, args);
635c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik    }
636c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik
63721c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim    private void dispatchMediaButton(RemoteUserInfo caller, Intent mediaButtonIntent) {
63821c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim        postToCallback(caller, CallbackMessageHandler.MSG_MEDIA_BUTTON, mediaButtonIntent, null);
6398ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik    }
6408ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik
64121c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim    private void dispatchMediaButtonDelayed(RemoteUserInfo info, Intent mediaButtonIntent,
64221c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim            long delay) {
64321c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim        postToCallbackDelayed(info, CallbackMessageHandler.MSG_PLAY_PAUSE_KEY_DOUBLE_TAP_TIMEOUT,
64421c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim                mediaButtonIntent, null, delay);
645563acea6665c45902bbc46db1a22c036344a818bRoboErik    }
646563acea6665c45902bbc46db1a22c036344a818bRoboErik
64721c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim    private void dispatchAdjustVolume(RemoteUserInfo caller, int direction) {
64821c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim        postToCallback(caller, CallbackMessageHandler.MSG_ADJUST_VOLUME, direction, null);
649563acea6665c45902bbc46db1a22c036344a818bRoboErik    }
650563acea6665c45902bbc46db1a22c036344a818bRoboErik
65121c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim    private void dispatchSetVolumeTo(RemoteUserInfo caller, int volume) {
65221c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim        postToCallback(caller, CallbackMessageHandler.MSG_SET_VOLUME, volume, null);
65321c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim    }
65421c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim
65521c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim    private void dispatchCommand(RemoteUserInfo caller, String command, Bundle args,
65621c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim            ResultReceiver resultCb) {
657f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal        Command cmd = new Command(command, args, resultCb);
65821c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim        postToCallback(caller, CallbackMessageHandler.MSG_COMMAND, cmd, null);
65901fe661ae5da3739215d93922412df4b24c859a2RoboErik    }
66001fe661ae5da3739215d93922412df4b24c859a2RoboErik
66121c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim    private void postToCallback(RemoteUserInfo caller, int what, Object obj, Bundle data) {
66221c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim        postToCallbackDelayed(caller, what, obj, data, 0);
66321c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim    }
66421c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim
66521c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim    private void postToCallbackDelayed(RemoteUserInfo caller, int what, Object obj, Bundle data,
66621c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim            long delay) {
66701fe661ae5da3739215d93922412df4b24c859a2RoboErik        synchronized (mLock) {
668bdcb3080b4c061a02a1a0a02f9afe20c1d29cf8aSungsoo Lim            if (mCallback != null) {
66921c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim                mCallback.post(caller, what, obj, data, delay);
67001fe661ae5da3739215d93922412df4b24c859a2RoboErik            }
67101fe661ae5da3739215d93922412df4b24c859a2RoboErik        }
67201fe661ae5da3739215d93922412df4b24c859a2RoboErik    }
67301fe661ae5da3739215d93922412df4b24c859a2RoboErik
67401fe661ae5da3739215d93922412df4b24c859a2RoboErik    /**
6753c45c29109d23981d8b707c809b3b43ce2e20fc3RoboErik     * Return true if this is considered an active playback state.
6763c45c29109d23981d8b707c809b3b43ce2e20fc3RoboErik     *
6773c45c29109d23981d8b707c809b3b43ce2e20fc3RoboErik     * @hide
6783c45c29109d23981d8b707c809b3b43ce2e20fc3RoboErik     */
6793c45c29109d23981d8b707c809b3b43ce2e20fc3RoboErik    public static boolean isActiveState(int state) {
6803c45c29109d23981d8b707c809b3b43ce2e20fc3RoboErik        switch (state) {
6813c45c29109d23981d8b707c809b3b43ce2e20fc3RoboErik            case PlaybackState.STATE_FAST_FORWARDING:
6823c45c29109d23981d8b707c809b3b43ce2e20fc3RoboErik            case PlaybackState.STATE_REWINDING:
6833c45c29109d23981d8b707c809b3b43ce2e20fc3RoboErik            case PlaybackState.STATE_SKIPPING_TO_PREVIOUS:
6843c45c29109d23981d8b707c809b3b43ce2e20fc3RoboErik            case PlaybackState.STATE_SKIPPING_TO_NEXT:
6853c45c29109d23981d8b707c809b3b43ce2e20fc3RoboErik            case PlaybackState.STATE_BUFFERING:
6863c45c29109d23981d8b707c809b3b43ce2e20fc3RoboErik            case PlaybackState.STATE_CONNECTING:
6873c45c29109d23981d8b707c809b3b43ce2e20fc3RoboErik            case PlaybackState.STATE_PLAYING:
6883c45c29109d23981d8b707c809b3b43ce2e20fc3RoboErik                return true;
6893c45c29109d23981d8b707c809b3b43ce2e20fc3RoboErik        }
6903c45c29109d23981d8b707c809b3b43ce2e20fc3RoboErik        return false;
6913c45c29109d23981d8b707c809b3b43ce2e20fc3RoboErik    }
6923c45c29109d23981d8b707c809b3b43ce2e20fc3RoboErik
6933c45c29109d23981d8b707c809b3b43ce2e20fc3RoboErik    /**
694dba34ba35cd2042d9a8fecfda56e2abe7a680badJeff Brown     * Represents an ongoing session. This may be passed to apps by the session
695dba34ba35cd2042d9a8fecfda56e2abe7a680badJeff Brown     * owner to allow them to create a {@link MediaController} to communicate with
696dba34ba35cd2042d9a8fecfda56e2abe7a680badJeff Brown     * the session.
697dba34ba35cd2042d9a8fecfda56e2abe7a680badJeff Brown     */
698dba34ba35cd2042d9a8fecfda56e2abe7a680badJeff Brown    public static final class Token implements Parcelable {
699aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik
700dba34ba35cd2042d9a8fecfda56e2abe7a680badJeff Brown        private ISessionController mBinder;
701dba34ba35cd2042d9a8fecfda56e2abe7a680badJeff Brown
702dba34ba35cd2042d9a8fecfda56e2abe7a680badJeff Brown        /**
703dba34ba35cd2042d9a8fecfda56e2abe7a680badJeff Brown         * @hide
704dba34ba35cd2042d9a8fecfda56e2abe7a680badJeff Brown         */
705dba34ba35cd2042d9a8fecfda56e2abe7a680badJeff Brown        public Token(ISessionController binder) {
706dba34ba35cd2042d9a8fecfda56e2abe7a680badJeff Brown            mBinder = binder;
707dba34ba35cd2042d9a8fecfda56e2abe7a680badJeff Brown        }
708dba34ba35cd2042d9a8fecfda56e2abe7a680badJeff Brown
709dba34ba35cd2042d9a8fecfda56e2abe7a680badJeff Brown        @Override
710dba34ba35cd2042d9a8fecfda56e2abe7a680badJeff Brown        public int describeContents() {
711dba34ba35cd2042d9a8fecfda56e2abe7a680badJeff Brown            return 0;
712dba34ba35cd2042d9a8fecfda56e2abe7a680badJeff Brown        }
713dba34ba35cd2042d9a8fecfda56e2abe7a680badJeff Brown
714dba34ba35cd2042d9a8fecfda56e2abe7a680badJeff Brown        @Override
715dba34ba35cd2042d9a8fecfda56e2abe7a680badJeff Brown        public void writeToParcel(Parcel dest, int flags) {
716dba34ba35cd2042d9a8fecfda56e2abe7a680badJeff Brown            dest.writeStrongBinder(mBinder.asBinder());
717dba34ba35cd2042d9a8fecfda56e2abe7a680badJeff Brown        }
718dba34ba35cd2042d9a8fecfda56e2abe7a680badJeff Brown
719aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik        @Override
720aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik        public int hashCode() {
721aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik            final int prime = 31;
722aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik            int result = 1;
723aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik            result = prime * result + ((mBinder == null) ? 0 : mBinder.asBinder().hashCode());
724aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik            return result;
725aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik        }
726aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik
727aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik        @Override
728aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik        public boolean equals(Object obj) {
729aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik            if (this == obj)
730aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik                return true;
731aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik            if (obj == null)
732aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik                return false;
733aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik            if (getClass() != obj.getClass())
734aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik                return false;
735aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik            Token other = (Token) obj;
736aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik            if (mBinder == null) {
737aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik                if (other.mBinder != null)
738aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik                    return false;
739aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik            } else if (!mBinder.asBinder().equals(other.mBinder.asBinder()))
740aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik                return false;
741aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik            return true;
742aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik        }
743aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik
744dba34ba35cd2042d9a8fecfda56e2abe7a680badJeff Brown        ISessionController getBinder() {
745dba34ba35cd2042d9a8fecfda56e2abe7a680badJeff Brown            return mBinder;
746dba34ba35cd2042d9a8fecfda56e2abe7a680badJeff Brown        }
747dba34ba35cd2042d9a8fecfda56e2abe7a680badJeff Brown
748dba34ba35cd2042d9a8fecfda56e2abe7a680badJeff Brown        public static final Parcelable.Creator<Token> CREATOR
749dba34ba35cd2042d9a8fecfda56e2abe7a680badJeff Brown                = new Parcelable.Creator<Token>() {
750dba34ba35cd2042d9a8fecfda56e2abe7a680badJeff Brown            @Override
751dba34ba35cd2042d9a8fecfda56e2abe7a680badJeff Brown            public Token createFromParcel(Parcel in) {
752dba34ba35cd2042d9a8fecfda56e2abe7a680badJeff Brown                return new Token(ISessionController.Stub.asInterface(in.readStrongBinder()));
753dba34ba35cd2042d9a8fecfda56e2abe7a680badJeff Brown            }
754dba34ba35cd2042d9a8fecfda56e2abe7a680badJeff Brown
755dba34ba35cd2042d9a8fecfda56e2abe7a680badJeff Brown            @Override
756dba34ba35cd2042d9a8fecfda56e2abe7a680badJeff Brown            public Token[] newArray(int size) {
757dba34ba35cd2042d9a8fecfda56e2abe7a680badJeff Brown                return new Token[size];
758dba34ba35cd2042d9a8fecfda56e2abe7a680badJeff Brown            }
759dba34ba35cd2042d9a8fecfda56e2abe7a680badJeff Brown        };
760dba34ba35cd2042d9a8fecfda56e2abe7a680badJeff Brown    }
761dba34ba35cd2042d9a8fecfda56e2abe7a680badJeff Brown
762dba34ba35cd2042d9a8fecfda56e2abe7a680badJeff Brown    /**
763477d1197c3c25c01ace7ea4494437c23720a2eb3RoboErik     * Receives media buttons, transport controls, and commands from controllers
764477d1197c3c25c01ace7ea4494437c23720a2eb3RoboErik     * and the system. A callback may be set using {@link #setCallback}.
76501fe661ae5da3739215d93922412df4b24c859a2RoboErik     */
76601fe661ae5da3739215d93922412df4b24c859a2RoboErik    public abstract static class Callback {
767b1e344eaab519aa9bc9db20c891831dfe2bf92abHyundo Moon
768477d1197c3c25c01ace7ea4494437c23720a2eb3RoboErik        private MediaSession mSession;
76974d002be26ec9800cb494471f0773493bc83d8f7Jaewan Kim        private CallbackMessageHandler mHandler;
77074d002be26ec9800cb494471f0773493bc83d8f7Jaewan Kim        private boolean mMediaPlayPauseKeyPending;
77101fe661ae5da3739215d93922412df4b24c859a2RoboErik
77201fe661ae5da3739215d93922412df4b24c859a2RoboErik        public Callback() {
77301fe661ae5da3739215d93922412df4b24c859a2RoboErik        }
77401fe661ae5da3739215d93922412df4b24c859a2RoboErik
77501fe661ae5da3739215d93922412df4b24c859a2RoboErik        /**
776f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal         * Called when a controller has sent a command to this session.
77701fe661ae5da3739215d93922412df4b24c859a2RoboErik         * The owner of the session may handle custom commands but is not
77801fe661ae5da3739215d93922412df4b24c859a2RoboErik         * required to.
77901fe661ae5da3739215d93922412df4b24c859a2RoboErik         *
780bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown         * @param command The command name.
781f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal         * @param args Optional parameters for the command, may be null.
782bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown         * @param cb A result receiver to which a result may be sent by the command, may be null.
78301fe661ae5da3739215d93922412df4b24c859a2RoboErik         */
784f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal        public void onCommand(@NonNull String command, @Nullable Bundle args,
785bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown                @Nullable ResultReceiver cb) {
78601fe661ae5da3739215d93922412df4b24c859a2RoboErik        }
78701fe661ae5da3739215d93922412df4b24c859a2RoboErik
788477d1197c3c25c01ace7ea4494437c23720a2eb3RoboErik        /**
789477d1197c3c25c01ace7ea4494437c23720a2eb3RoboErik         * Called when a media button is pressed and this session has the
790477d1197c3c25c01ace7ea4494437c23720a2eb3RoboErik         * highest priority or a controller sends a media button event to the
791477d1197c3c25c01ace7ea4494437c23720a2eb3RoboErik         * session. The default behavior will call the relevant method if the
792477d1197c3c25c01ace7ea4494437c23720a2eb3RoboErik         * action for it was set.
793477d1197c3c25c01ace7ea4494437c23720a2eb3RoboErik         * <p>
794477d1197c3c25c01ace7ea4494437c23720a2eb3RoboErik         * The intent will be of type {@link Intent#ACTION_MEDIA_BUTTON} with a
795477d1197c3c25c01ace7ea4494437c23720a2eb3RoboErik         * KeyEvent in {@link Intent#EXTRA_KEY_EVENT}
796477d1197c3c25c01ace7ea4494437c23720a2eb3RoboErik         *
797477d1197c3c25c01ace7ea4494437c23720a2eb3RoboErik         * @param mediaButtonIntent an intent containing the KeyEvent as an
798477d1197c3c25c01ace7ea4494437c23720a2eb3RoboErik         *            extra
799cd74270da7a7320904f14a465b8902dd5ea56f1dRoboErik         * @return True if the event was handled, false otherwise.
800477d1197c3c25c01ace7ea4494437c23720a2eb3RoboErik         */
801477d1197c3c25c01ace7ea4494437c23720a2eb3RoboErik        public boolean onMediaButtonEvent(@NonNull Intent mediaButtonIntent) {
80274d002be26ec9800cb494471f0773493bc83d8f7Jaewan Kim            if (mSession != null && mHandler != null
803477d1197c3c25c01ace7ea4494437c23720a2eb3RoboErik                    && Intent.ACTION_MEDIA_BUTTON.equals(mediaButtonIntent.getAction())) {
804477d1197c3c25c01ace7ea4494437c23720a2eb3RoboErik                KeyEvent ke = mediaButtonIntent.getParcelableExtra(Intent.EXTRA_KEY_EVENT);
805477d1197c3c25c01ace7ea4494437c23720a2eb3RoboErik                if (ke != null && ke.getAction() == KeyEvent.ACTION_DOWN) {
806477d1197c3c25c01ace7ea4494437c23720a2eb3RoboErik                    PlaybackState state = mSession.mPlaybackState;
807477d1197c3c25c01ace7ea4494437c23720a2eb3RoboErik                    long validActions = state == null ? 0 : state.getActions();
808477d1197c3c25c01ace7ea4494437c23720a2eb3RoboErik                    switch (ke.getKeyCode()) {
80974d002be26ec9800cb494471f0773493bc83d8f7Jaewan Kim                        case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
81074d002be26ec9800cb494471f0773493bc83d8f7Jaewan Kim                        case KeyEvent.KEYCODE_HEADSETHOOK:
81174d002be26ec9800cb494471f0773493bc83d8f7Jaewan Kim                            if (ke.getRepeatCount() > 0) {
81274d002be26ec9800cb494471f0773493bc83d8f7Jaewan Kim                                // Consider long-press as a single tap.
81374d002be26ec9800cb494471f0773493bc83d8f7Jaewan Kim                                handleMediaPlayPauseKeySingleTapIfPending();
81474d002be26ec9800cb494471f0773493bc83d8f7Jaewan Kim                            } else if (mMediaPlayPauseKeyPending) {
81574d002be26ec9800cb494471f0773493bc83d8f7Jaewan Kim                                // Consider double tap as the next.
81674d002be26ec9800cb494471f0773493bc83d8f7Jaewan Kim                                mHandler.removeMessages(CallbackMessageHandler
81774d002be26ec9800cb494471f0773493bc83d8f7Jaewan Kim                                        .MSG_PLAY_PAUSE_KEY_DOUBLE_TAP_TIMEOUT);
81874d002be26ec9800cb494471f0773493bc83d8f7Jaewan Kim                                mMediaPlayPauseKeyPending = false;
81974d002be26ec9800cb494471f0773493bc83d8f7Jaewan Kim                                if ((validActions & PlaybackState.ACTION_SKIP_TO_NEXT) != 0) {
82074d002be26ec9800cb494471f0773493bc83d8f7Jaewan Kim                                    onSkipToNext();
82174d002be26ec9800cb494471f0773493bc83d8f7Jaewan Kim                                }
82274d002be26ec9800cb494471f0773493bc83d8f7Jaewan Kim                            } else {
82374d002be26ec9800cb494471f0773493bc83d8f7Jaewan Kim                                mMediaPlayPauseKeyPending = true;
82421c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim                                mSession.dispatchMediaButtonDelayed(
82521c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim                                        mSession.getCurrentControllerInfo(),
82621c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim                                        mediaButtonIntent, ViewConfiguration.getDoubleTapTimeout());
82774d002be26ec9800cb494471f0773493bc83d8f7Jaewan Kim                            }
82874d002be26ec9800cb494471f0773493bc83d8f7Jaewan Kim                            return true;
82974d002be26ec9800cb494471f0773493bc83d8f7Jaewan Kim                        default:
83074d002be26ec9800cb494471f0773493bc83d8f7Jaewan Kim                            // If another key is pressed within double tap timeout, consider the
83174d002be26ec9800cb494471f0773493bc83d8f7Jaewan Kim                            // pending play/pause as a single tap to handle media keys in order.
83274d002be26ec9800cb494471f0773493bc83d8f7Jaewan Kim                            handleMediaPlayPauseKeySingleTapIfPending();
83374d002be26ec9800cb494471f0773493bc83d8f7Jaewan Kim                            break;
83474d002be26ec9800cb494471f0773493bc83d8f7Jaewan Kim                    }
83574d002be26ec9800cb494471f0773493bc83d8f7Jaewan Kim
83674d002be26ec9800cb494471f0773493bc83d8f7Jaewan Kim                    switch (ke.getKeyCode()) {
837477d1197c3c25c01ace7ea4494437c23720a2eb3RoboErik                        case KeyEvent.KEYCODE_MEDIA_PLAY:
838477d1197c3c25c01ace7ea4494437c23720a2eb3RoboErik                            if ((validActions & PlaybackState.ACTION_PLAY) != 0) {
839477d1197c3c25c01ace7ea4494437c23720a2eb3RoboErik                                onPlay();
840cd74270da7a7320904f14a465b8902dd5ea56f1dRoboErik                                return true;
841477d1197c3c25c01ace7ea4494437c23720a2eb3RoboErik                            }
842477d1197c3c25c01ace7ea4494437c23720a2eb3RoboErik                            break;
843477d1197c3c25c01ace7ea4494437c23720a2eb3RoboErik                        case KeyEvent.KEYCODE_MEDIA_PAUSE:
844477d1197c3c25c01ace7ea4494437c23720a2eb3RoboErik                            if ((validActions & PlaybackState.ACTION_PAUSE) != 0) {
845477d1197c3c25c01ace7ea4494437c23720a2eb3RoboErik                                onPause();
846cd74270da7a7320904f14a465b8902dd5ea56f1dRoboErik                                return true;
847477d1197c3c25c01ace7ea4494437c23720a2eb3RoboErik                            }
848477d1197c3c25c01ace7ea4494437c23720a2eb3RoboErik                            break;
849477d1197c3c25c01ace7ea4494437c23720a2eb3RoboErik                        case KeyEvent.KEYCODE_MEDIA_NEXT:
850477d1197c3c25c01ace7ea4494437c23720a2eb3RoboErik                            if ((validActions & PlaybackState.ACTION_SKIP_TO_NEXT) != 0) {
851477d1197c3c25c01ace7ea4494437c23720a2eb3RoboErik                                onSkipToNext();
852cd74270da7a7320904f14a465b8902dd5ea56f1dRoboErik                                return true;
853477d1197c3c25c01ace7ea4494437c23720a2eb3RoboErik                            }
854477d1197c3c25c01ace7ea4494437c23720a2eb3RoboErik                            break;
855477d1197c3c25c01ace7ea4494437c23720a2eb3RoboErik                        case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
856477d1197c3c25c01ace7ea4494437c23720a2eb3RoboErik                            if ((validActions & PlaybackState.ACTION_SKIP_TO_PREVIOUS) != 0) {
857477d1197c3c25c01ace7ea4494437c23720a2eb3RoboErik                                onSkipToPrevious();
858cd74270da7a7320904f14a465b8902dd5ea56f1dRoboErik                                return true;
859477d1197c3c25c01ace7ea4494437c23720a2eb3RoboErik                            }
860477d1197c3c25c01ace7ea4494437c23720a2eb3RoboErik                            break;
861477d1197c3c25c01ace7ea4494437c23720a2eb3RoboErik                        case KeyEvent.KEYCODE_MEDIA_STOP:
862477d1197c3c25c01ace7ea4494437c23720a2eb3RoboErik                            if ((validActions & PlaybackState.ACTION_STOP) != 0) {
863477d1197c3c25c01ace7ea4494437c23720a2eb3RoboErik                                onStop();
864cd74270da7a7320904f14a465b8902dd5ea56f1dRoboErik                                return true;
865477d1197c3c25c01ace7ea4494437c23720a2eb3RoboErik                            }
866477d1197c3c25c01ace7ea4494437c23720a2eb3RoboErik                            break;
867477d1197c3c25c01ace7ea4494437c23720a2eb3RoboErik                        case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD:
868477d1197c3c25c01ace7ea4494437c23720a2eb3RoboErik                            if ((validActions & PlaybackState.ACTION_FAST_FORWARD) != 0) {
869477d1197c3c25c01ace7ea4494437c23720a2eb3RoboErik                                onFastForward();
870cd74270da7a7320904f14a465b8902dd5ea56f1dRoboErik                                return true;
871477d1197c3c25c01ace7ea4494437c23720a2eb3RoboErik                            }
872477d1197c3c25c01ace7ea4494437c23720a2eb3RoboErik                            break;
873477d1197c3c25c01ace7ea4494437c23720a2eb3RoboErik                        case KeyEvent.KEYCODE_MEDIA_REWIND:
874477d1197c3c25c01ace7ea4494437c23720a2eb3RoboErik                            if ((validActions & PlaybackState.ACTION_REWIND) != 0) {
875477d1197c3c25c01ace7ea4494437c23720a2eb3RoboErik                                onRewind();
876cd74270da7a7320904f14a465b8902dd5ea56f1dRoboErik                                return true;
877477d1197c3c25c01ace7ea4494437c23720a2eb3RoboErik                            }
878477d1197c3c25c01ace7ea4494437c23720a2eb3RoboErik                            break;
879477d1197c3c25c01ace7ea4494437c23720a2eb3RoboErik                    }
880477d1197c3c25c01ace7ea4494437c23720a2eb3RoboErik                }
881477d1197c3c25c01ace7ea4494437c23720a2eb3RoboErik            }
882477d1197c3c25c01ace7ea4494437c23720a2eb3RoboErik            return false;
883477d1197c3c25c01ace7ea4494437c23720a2eb3RoboErik        }
884c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik
88574d002be26ec9800cb494471f0773493bc83d8f7Jaewan Kim        private void handleMediaPlayPauseKeySingleTapIfPending() {
88674d002be26ec9800cb494471f0773493bc83d8f7Jaewan Kim            if (!mMediaPlayPauseKeyPending) {
88774d002be26ec9800cb494471f0773493bc83d8f7Jaewan Kim                return;
88874d002be26ec9800cb494471f0773493bc83d8f7Jaewan Kim            }
88974d002be26ec9800cb494471f0773493bc83d8f7Jaewan Kim            mMediaPlayPauseKeyPending = false;
89074d002be26ec9800cb494471f0773493bc83d8f7Jaewan Kim            mHandler.removeMessages(CallbackMessageHandler.MSG_PLAY_PAUSE_KEY_DOUBLE_TAP_TIMEOUT);
89174d002be26ec9800cb494471f0773493bc83d8f7Jaewan Kim            PlaybackState state = mSession.mPlaybackState;
89274d002be26ec9800cb494471f0773493bc83d8f7Jaewan Kim            long validActions = state == null ? 0 : state.getActions();
89374d002be26ec9800cb494471f0773493bc83d8f7Jaewan Kim            boolean isPlaying = state != null
89474d002be26ec9800cb494471f0773493bc83d8f7Jaewan Kim                    && state.getState() == PlaybackState.STATE_PLAYING;
89574d002be26ec9800cb494471f0773493bc83d8f7Jaewan Kim            boolean canPlay = (validActions & (PlaybackState.ACTION_PLAY_PAUSE
89674d002be26ec9800cb494471f0773493bc83d8f7Jaewan Kim                        | PlaybackState.ACTION_PLAY)) != 0;
89774d002be26ec9800cb494471f0773493bc83d8f7Jaewan Kim            boolean canPause = (validActions & (PlaybackState.ACTION_PLAY_PAUSE
89874d002be26ec9800cb494471f0773493bc83d8f7Jaewan Kim                        | PlaybackState.ACTION_PAUSE)) != 0;
89974d002be26ec9800cb494471f0773493bc83d8f7Jaewan Kim            if (isPlaying && canPause) {
90074d002be26ec9800cb494471f0773493bc83d8f7Jaewan Kim                onPause();
90174d002be26ec9800cb494471f0773493bc83d8f7Jaewan Kim            } else if (!isPlaying && canPlay) {
90274d002be26ec9800cb494471f0773493bc83d8f7Jaewan Kim                onPlay();
90374d002be26ec9800cb494471f0773493bc83d8f7Jaewan Kim            }
90474d002be26ec9800cb494471f0773493bc83d8f7Jaewan Kim        }
90574d002be26ec9800cb494471f0773493bc83d8f7Jaewan Kim
906c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik        /**
907f9f240ab7d9918a14437d3ae63ae959e4ff906ccDonghyun Cho         * Override to handle requests to prepare playback. During the preparation, a session should
908f9f240ab7d9918a14437d3ae63ae959e4ff906ccDonghyun Cho         * not hold audio focus in order to allow other sessions play seamlessly. The state of
909f9f240ab7d9918a14437d3ae63ae959e4ff906ccDonghyun Cho         * playback should be updated to {@link PlaybackState#STATE_PAUSED} after the preparation is
910f9f240ab7d9918a14437d3ae63ae959e4ff906ccDonghyun Cho         * done.
911c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik         */
91222188f118754c3b31c13d2f94daf718f111d92afDonghyun Cho        public void onPrepare() {
913c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik        }
914c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik
915c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik        /**
91622188f118754c3b31c13d2f94daf718f111d92afDonghyun Cho         * Override to handle requests to prepare for playing a specific mediaId that was provided
917f9f240ab7d9918a14437d3ae63ae959e4ff906ccDonghyun Cho         * by your app's {@link MediaBrowserService}. During the preparation, a session should not
918f9f240ab7d9918a14437d3ae63ae959e4ff906ccDonghyun Cho         * hold audio focus in order to allow other sessions play seamlessly. The state of playback
919f9f240ab7d9918a14437d3ae63ae959e4ff906ccDonghyun Cho         * should be updated to {@link PlaybackState#STATE_PAUSED} after the preparation is done.
920f9f240ab7d9918a14437d3ae63ae959e4ff906ccDonghyun Cho         * The playback of the prepared content should start in the implementation of
921f9f240ab7d9918a14437d3ae63ae959e4ff906ccDonghyun Cho         * {@link #onPlay}. Override {@link #onPlayFromMediaId} to handle requests for starting
922f9f240ab7d9918a14437d3ae63ae959e4ff906ccDonghyun Cho         * playback without preparation.
923f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal         */
92422188f118754c3b31c13d2f94daf718f111d92afDonghyun Cho        public void onPrepareFromMediaId(String mediaId, Bundle extras) {
92522188f118754c3b31c13d2f94daf718f111d92afDonghyun Cho        }
92622188f118754c3b31c13d2f94daf718f111d92afDonghyun Cho
92722188f118754c3b31c13d2f94daf718f111d92afDonghyun Cho        /**
928f9f240ab7d9918a14437d3ae63ae959e4ff906ccDonghyun Cho         * Override to handle requests to prepare playback from a search query. An empty query
929f9f240ab7d9918a14437d3ae63ae959e4ff906ccDonghyun Cho         * indicates that the app may prepare any music. The implementation should attempt to make a
930f9f240ab7d9918a14437d3ae63ae959e4ff906ccDonghyun Cho         * smart choice about what to play. During the preparation, a session should not hold audio
931f9f240ab7d9918a14437d3ae63ae959e4ff906ccDonghyun Cho         * focus in order to allow other sessions play seamlessly. The state of playback should be
932f9f240ab7d9918a14437d3ae63ae959e4ff906ccDonghyun Cho         * updated to {@link PlaybackState#STATE_PAUSED} after the preparation is done. The playback
933f9f240ab7d9918a14437d3ae63ae959e4ff906ccDonghyun Cho         * of the prepared content should start in the implementation of {@link #onPlay}. Override
934f9f240ab7d9918a14437d3ae63ae959e4ff906ccDonghyun Cho         * {@link #onPlayFromSearch} to handle requests for starting playback without preparation.
93522188f118754c3b31c13d2f94daf718f111d92afDonghyun Cho         */
93622188f118754c3b31c13d2f94daf718f111d92afDonghyun Cho        public void onPrepareFromSearch(String query, Bundle extras) {
93722188f118754c3b31c13d2f94daf718f111d92afDonghyun Cho        }
93822188f118754c3b31c13d2f94daf718f111d92afDonghyun Cho
93922188f118754c3b31c13d2f94daf718f111d92afDonghyun Cho        /**
94022188f118754c3b31c13d2f94daf718f111d92afDonghyun Cho         * Override to handle requests to prepare a specific media item represented by a URI.
941f9f240ab7d9918a14437d3ae63ae959e4ff906ccDonghyun Cho         * During the preparation, a session should not hold audio focus in order to allow
942f9f240ab7d9918a14437d3ae63ae959e4ff906ccDonghyun Cho         * other sessions play seamlessly. The state of playback should be updated to
943f9f240ab7d9918a14437d3ae63ae959e4ff906ccDonghyun Cho         * {@link PlaybackState#STATE_PAUSED} after the preparation is done.
944f9f240ab7d9918a14437d3ae63ae959e4ff906ccDonghyun Cho         * The playback of the prepared content should start in the implementation of
945f9f240ab7d9918a14437d3ae63ae959e4ff906ccDonghyun Cho         * {@link #onPlay}. Override {@link #onPlayFromUri} to handle requests
94622188f118754c3b31c13d2f94daf718f111d92afDonghyun Cho         * for starting playback without preparation.
94722188f118754c3b31c13d2f94daf718f111d92afDonghyun Cho         */
94822188f118754c3b31c13d2f94daf718f111d92afDonghyun Cho        public void onPrepareFromUri(Uri uri, Bundle extras) {
94922188f118754c3b31c13d2f94daf718f111d92afDonghyun Cho        }
95022188f118754c3b31c13d2f94daf718f111d92afDonghyun Cho
95122188f118754c3b31c13d2f94daf718f111d92afDonghyun Cho        /**
95222188f118754c3b31c13d2f94daf718f111d92afDonghyun Cho         * Override to handle requests to begin playback.
95322188f118754c3b31c13d2f94daf718f111d92afDonghyun Cho         */
95422188f118754c3b31c13d2f94daf718f111d92afDonghyun Cho        public void onPlay() {
955f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal        }
956f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal
957f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal        /**
9584b253d2bcd62ea2a9afb067c1f1363fa7b752185RoboErik         * Override to handle requests to begin playback from a search query. An
9594b253d2bcd62ea2a9afb067c1f1363fa7b752185RoboErik         * empty query indicates that the app may play any music. The
9604b253d2bcd62ea2a9afb067c1f1363fa7b752185RoboErik         * implementation should attempt to make a smart choice about what to
9614b253d2bcd62ea2a9afb067c1f1363fa7b752185RoboErik         * play.
962f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal         */
963f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal        public void onPlayFromSearch(String query, Bundle extras) {
964f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal        }
965f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal
966f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal        /**
96722188f118754c3b31c13d2f94daf718f111d92afDonghyun Cho         * Override to handle requests to play a specific mediaId that was
96822188f118754c3b31c13d2f94daf718f111d92afDonghyun Cho         * provided by your app's {@link MediaBrowserService}.
96922188f118754c3b31c13d2f94daf718f111d92afDonghyun Cho         */
97022188f118754c3b31c13d2f94daf718f111d92afDonghyun Cho        public void onPlayFromMediaId(String mediaId, Bundle extras) {
97122188f118754c3b31c13d2f94daf718f111d92afDonghyun Cho        }
97222188f118754c3b31c13d2f94daf718f111d92afDonghyun Cho
97322188f118754c3b31c13d2f94daf718f111d92afDonghyun Cho        /**
974c2045470a343923b0d74ddbd6a6b80fcf6652d66P.Y. Laligand         * Override to handle requests to play a specific media item represented by a URI.
975c2045470a343923b0d74ddbd6a6b80fcf6652d66P.Y. Laligand         */
976c2045470a343923b0d74ddbd6a6b80fcf6652d66P.Y. Laligand        public void onPlayFromUri(Uri uri, Bundle extras) {
977c2045470a343923b0d74ddbd6a6b80fcf6652d66P.Y. Laligand        }
978c2045470a343923b0d74ddbd6a6b80fcf6652d66P.Y. Laligand
979c2045470a343923b0d74ddbd6a6b80fcf6652d66P.Y. Laligand        /**
980a66c40bf6e0fb79ead6d8a9fc29c5671fa7b1206RoboErik         * Override to handle requests to play an item with a given id from the
981a66c40bf6e0fb79ead6d8a9fc29c5671fa7b1206RoboErik         * play queue.
982f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal         */
9833625bf72cb8bcf3c7f8f8cd8d708d7206824cc62RoboErik        public void onSkipToQueueItem(long id) {
984f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal        }
985f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal
986f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal        /**
987c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik         * Override to handle requests to pause playback.
988c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik         */
989c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik        public void onPause() {
990c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik        }
991c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik
992c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik        /**
993c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik         * Override to handle requests to skip to the next media item.
994c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik         */
995c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik        public void onSkipToNext() {
996c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik        }
997c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik
998c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik        /**
999c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik         * Override to handle requests to skip to the previous media item.
1000c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik         */
1001c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik        public void onSkipToPrevious() {
1002c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik        }
1003c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik
1004c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik        /**
1005c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik         * Override to handle requests to fast forward.
1006c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik         */
1007c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik        public void onFastForward() {
1008c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik        }
1009c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik
1010c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik        /**
1011c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik         * Override to handle requests to rewind.
1012c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik         */
1013c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik        public void onRewind() {
1014c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik        }
1015c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik
1016c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik        /**
1017c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik         * Override to handle requests to stop playback.
1018c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik         */
1019c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik        public void onStop() {
1020c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik        }
1021c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik
1022c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik        /**
1023c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik         * Override to handle requests to seek to a specific position in ms.
1024c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik         *
1025c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik         * @param pos New position to move to, in milliseconds.
1026c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik         */
1027c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik        public void onSeekTo(long pos) {
1028c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik        }
1029c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik
1030c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik        /**
1031c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik         * Override to handle the item being rated.
1032c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik         *
1033c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik         * @param rating
1034c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik         */
1035bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown        public void onSetRating(@NonNull Rating rating) {
1036c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik        }
1037f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal
1038f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal        /**
1039f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal         * Called when a {@link MediaController} wants a {@link PlaybackState.CustomAction} to be
1040f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal         * performed.
1041f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal         *
1042f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal         * @param action The action that was originally sent in the
1043f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal         *               {@link PlaybackState.CustomAction}.
1044f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal         * @param extras Optional extras specified by the {@link MediaController}.
1045f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal         */
1046f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal        public void onCustomAction(@NonNull String action, @Nullable Bundle extras) {
1047f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal        }
1048c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik    }
1049c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik
1050c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik    /**
105101fe661ae5da3739215d93922412df4b24c859a2RoboErik     * @hide
105201fe661ae5da3739215d93922412df4b24c859a2RoboErik     */
105307c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik    public static class CallbackStub extends ISessionCallback.Stub {
105442ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErik        private WeakReference<MediaSession> mMediaSession;
105501fe661ae5da3739215d93922412df4b24c859a2RoboErik
1056ca58ddf7c82dd0857de0c3d49d7eb87a842ee4ceRoboErik        public CallbackStub(MediaSession session) {
1057b1e344eaab519aa9bc9db20c891831dfe2bf92abHyundo Moon            mMediaSession = new WeakReference<>(session);
105801fe661ae5da3739215d93922412df4b24c859a2RoboErik        }
105901fe661ae5da3739215d93922412df4b24c859a2RoboErik
106021c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim        private static RemoteUserInfo createRemoteUserInfo(String packageName, int pid, int uid,
106121c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim                ISessionControllerCallback caller) {
106221c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim            return new RemoteUserInfo(packageName, pid, uid,
106321c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim                    caller != null ? caller.asBinder() : null);
106421c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim        }
106521c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim
106601fe661ae5da3739215d93922412df4b24c859a2RoboErik        @Override
106721c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim        public void onCommand(String packageName, int pid, int uid,
106821c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim                ISessionControllerCallback caller, String command, Bundle args, ResultReceiver cb) {
106942ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErik            MediaSession session = mMediaSession.get();
10708ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik            if (session != null) {
107121c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim                session.dispatchCommand(createRemoteUserInfo(packageName, pid, uid, caller),
107221c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim                        command, args, cb);
10738ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik            }
107401fe661ae5da3739215d93922412df4b24c859a2RoboErik        }
107501fe661ae5da3739215d93922412df4b24c859a2RoboErik
107601fe661ae5da3739215d93922412df4b24c859a2RoboErik        @Override
1077b1e344eaab519aa9bc9db20c891831dfe2bf92abHyundo Moon        public void onMediaButton(String packageName, int pid, int uid, Intent mediaButtonIntent,
1078b1e344eaab519aa9bc9db20c891831dfe2bf92abHyundo Moon                int sequenceNumber, ResultReceiver cb) {
107942ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErik            MediaSession session = mMediaSession.get();
1080418c10ca9df1505509afeffd558cd92fc97bc635RoboErik            try {
1081418c10ca9df1505509afeffd558cd92fc97bc635RoboErik                if (session != null) {
108221c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim                    session.dispatchMediaButton(createRemoteUserInfo(packageName, pid, uid, null),
108321c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim                            mediaButtonIntent);
1084418c10ca9df1505509afeffd558cd92fc97bc635RoboErik                }
1085418c10ca9df1505509afeffd558cd92fc97bc635RoboErik            } finally {
1086418c10ca9df1505509afeffd558cd92fc97bc635RoboErik                if (cb != null) {
1087418c10ca9df1505509afeffd558cd92fc97bc635RoboErik                    cb.send(sequenceNumber, null);
1088418c10ca9df1505509afeffd558cd92fc97bc635RoboErik                }
10898a2cfc309ab9126e90022916967c65a793c034f0RoboErik            }
109001fe661ae5da3739215d93922412df4b24c859a2RoboErik        }
109101fe661ae5da3739215d93922412df4b24c859a2RoboErik
109201fe661ae5da3739215d93922412df4b24c859a2RoboErik        @Override
109321c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim        public void onMediaButtonFromController(String packageName, int pid, int uid,
109421c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim                ISessionControllerCallback caller, Intent mediaButtonIntent) {
109522188f118754c3b31c13d2f94daf718f111d92afDonghyun Cho            MediaSession session = mMediaSession.get();
109622188f118754c3b31c13d2f94daf718f111d92afDonghyun Cho            if (session != null) {
109721c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim                session.dispatchMediaButton(createRemoteUserInfo(packageName, pid, uid, caller),
109821c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim                        mediaButtonIntent);
109922188f118754c3b31c13d2f94daf718f111d92afDonghyun Cho            }
110022188f118754c3b31c13d2f94daf718f111d92afDonghyun Cho        }
110122188f118754c3b31c13d2f94daf718f111d92afDonghyun Cho
110222188f118754c3b31c13d2f94daf718f111d92afDonghyun Cho        @Override
110321c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim        public void onPrepare(String packageName, int pid, int uid,
110421c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim                ISessionControllerCallback caller) {
110521c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim            MediaSession session = mMediaSession.get();
110621c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim            if (session != null) {
110721c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim                session.dispatchPrepare(createRemoteUserInfo(packageName, pid, uid, caller));
110821c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim            }
110921c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim        }
111021c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim
111121c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim        @Override
111221c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim        public void onPrepareFromMediaId(String packageName, int pid, int uid,
111321c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim                ISessionControllerCallback caller, String mediaId,
1114b1e344eaab519aa9bc9db20c891831dfe2bf92abHyundo Moon                Bundle extras) {
111522188f118754c3b31c13d2f94daf718f111d92afDonghyun Cho            MediaSession session = mMediaSession.get();
111622188f118754c3b31c13d2f94daf718f111d92afDonghyun Cho            if (session != null) {
1117b1e344eaab519aa9bc9db20c891831dfe2bf92abHyundo Moon                session.dispatchPrepareFromMediaId(
111821c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim                        createRemoteUserInfo(packageName, pid, uid, caller), mediaId, extras);
111922188f118754c3b31c13d2f94daf718f111d92afDonghyun Cho            }
112022188f118754c3b31c13d2f94daf718f111d92afDonghyun Cho        }
112122188f118754c3b31c13d2f94daf718f111d92afDonghyun Cho
112222188f118754c3b31c13d2f94daf718f111d92afDonghyun Cho        @Override
112321c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim        public void onPrepareFromSearch(String packageName, int pid, int uid,
112421c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim                ISessionControllerCallback caller, String query,
1125b1e344eaab519aa9bc9db20c891831dfe2bf92abHyundo Moon                Bundle extras) {
112622188f118754c3b31c13d2f94daf718f111d92afDonghyun Cho            MediaSession session = mMediaSession.get();
112722188f118754c3b31c13d2f94daf718f111d92afDonghyun Cho            if (session != null) {
1128b1e344eaab519aa9bc9db20c891831dfe2bf92abHyundo Moon                session.dispatchPrepareFromSearch(
112921c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim                        createRemoteUserInfo(packageName, pid, uid, caller), query, extras);
113022188f118754c3b31c13d2f94daf718f111d92afDonghyun Cho            }
113122188f118754c3b31c13d2f94daf718f111d92afDonghyun Cho        }
113222188f118754c3b31c13d2f94daf718f111d92afDonghyun Cho
113322188f118754c3b31c13d2f94daf718f111d92afDonghyun Cho        @Override
113421c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim        public void onPrepareFromUri(String packageName, int pid, int uid,
113521c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim                ISessionControllerCallback caller, Uri uri, Bundle extras) {
113622188f118754c3b31c13d2f94daf718f111d92afDonghyun Cho            MediaSession session = mMediaSession.get();
113722188f118754c3b31c13d2f94daf718f111d92afDonghyun Cho            if (session != null) {
113821c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim                session.dispatchPrepareFromUri(createRemoteUserInfo(packageName, pid, uid, caller),
113921c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim                        uri, extras);
114022188f118754c3b31c13d2f94daf718f111d92afDonghyun Cho            }
114122188f118754c3b31c13d2f94daf718f111d92afDonghyun Cho        }
114222188f118754c3b31c13d2f94daf718f111d92afDonghyun Cho
114322188f118754c3b31c13d2f94daf718f111d92afDonghyun Cho        @Override
114421c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim        public void onPlay(String packageName, int pid, int uid,
114521c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim                ISessionControllerCallback caller) {
114642ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErik            MediaSession session = mMediaSession.get();
11478ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik            if (session != null) {
114821c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim                session.dispatchPlay(createRemoteUserInfo(packageName, pid, uid, caller));
11498ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik            }
11508ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        }
11518ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik
11528ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        @Override
115321c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim        public void onPlayFromMediaId(String packageName, int pid, int uid,
115421c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim                ISessionControllerCallback caller, String mediaId,
1155b1e344eaab519aa9bc9db20c891831dfe2bf92abHyundo Moon                Bundle extras) {
1156f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal            MediaSession session = mMediaSession.get();
1157f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal            if (session != null) {
115821c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim                session.dispatchPlayFromMediaId(createRemoteUserInfo(packageName, pid, uid, caller),
115921c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim                        mediaId, extras);
1160f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal            }
1161f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal        }
1162f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal
1163f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal        @Override
116421c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim        public void onPlayFromSearch(String packageName, int pid, int uid,
116521c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim                ISessionControllerCallback caller, String query,
1166b1e344eaab519aa9bc9db20c891831dfe2bf92abHyundo Moon                Bundle extras) {
1167f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal            MediaSession session = mMediaSession.get();
1168f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal            if (session != null) {
116921c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim                session.dispatchPlayFromSearch(createRemoteUserInfo(packageName, pid, uid, caller),
117021c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim                        query, extras);
1171f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal            }
1172f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal        }
1173f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal
1174f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal        @Override
117521c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim        public void onPlayFromUri(String packageName, int pid, int uid,
117621c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim                ISessionControllerCallback caller, Uri uri, Bundle extras) {
1177c2045470a343923b0d74ddbd6a6b80fcf6652d66P.Y. Laligand            MediaSession session = mMediaSession.get();
1178c2045470a343923b0d74ddbd6a6b80fcf6652d66P.Y. Laligand            if (session != null) {
117921c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim                session.dispatchPlayFromUri(createRemoteUserInfo(packageName, pid, uid, caller),
118021c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim                        uri, extras);
1181c2045470a343923b0d74ddbd6a6b80fcf6652d66P.Y. Laligand            }
1182c2045470a343923b0d74ddbd6a6b80fcf6652d66P.Y. Laligand        }
1183c2045470a343923b0d74ddbd6a6b80fcf6652d66P.Y. Laligand
1184c2045470a343923b0d74ddbd6a6b80fcf6652d66P.Y. Laligand        @Override
118521c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim        public void onSkipToTrack(String packageName, int pid, int uid,
118621c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim                ISessionControllerCallback caller, long id) {
1187f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal            MediaSession session = mMediaSession.get();
1188f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal            if (session != null) {
118921c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim                session.dispatchSkipToItem(createRemoteUserInfo(packageName, pid, uid, caller), id);
1190f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal            }
1191f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal        }
1192f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal
1193f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal        @Override
119421c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim        public void onPause(String packageName, int pid, int uid,
119521c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim                ISessionControllerCallback caller) {
119642ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErik            MediaSession session = mMediaSession.get();
11978ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik            if (session != null) {
119821c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim                session.dispatchPause(createRemoteUserInfo(packageName, pid, uid, caller));
11998ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik            }
12008ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        }
12018ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik
12028ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        @Override
120321c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim        public void onStop(String packageName, int pid, int uid,
120421c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim                ISessionControllerCallback caller) {
120542ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErik            MediaSession session = mMediaSession.get();
12068ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik            if (session != null) {
120721c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim                session.dispatchStop(createRemoteUserInfo(packageName, pid, uid, caller));
12088ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik            }
12098ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        }
12108ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik
12118ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        @Override
121221c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim        public void onNext(String packageName, int pid, int uid,
121321c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim                ISessionControllerCallback caller) {
121442ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErik            MediaSession session = mMediaSession.get();
12158ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik            if (session != null) {
121621c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim                session.dispatchNext(createRemoteUserInfo(packageName, pid, uid, caller));
12178ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik            }
12188ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        }
12198ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik
12208ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        @Override
122121c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim        public void onPrevious(String packageName, int pid, int uid,
122221c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim                ISessionControllerCallback caller) {
122342ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErik            MediaSession session = mMediaSession.get();
12248ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik            if (session != null) {
122521c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim                session.dispatchPrevious(createRemoteUserInfo(packageName, pid, uid, caller));
12268ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik            }
12278ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        }
12288ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik
12298ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        @Override
123021c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim        public void onFastForward(String packageName, int pid, int uid,
123121c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim                ISessionControllerCallback caller) {
123242ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErik            MediaSession session = mMediaSession.get();
12338ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik            if (session != null) {
123421c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim                session.dispatchFastForward(createRemoteUserInfo(packageName, pid, uid, caller));
12358ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik            }
12368ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        }
12378ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik
12388ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        @Override
123921c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim        public void onRewind(String packageName, int pid, int uid,
124021c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim                ISessionControllerCallback caller) {
124142ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErik            MediaSession session = mMediaSession.get();
12428ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik            if (session != null) {
124321c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim                session.dispatchRewind(createRemoteUserInfo(packageName, pid, uid, caller));
12448ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik            }
12458ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        }
12468ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik
12478ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        @Override
124821c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim        public void onSeekTo(String packageName, int pid, int uid,
124921c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim                ISessionControllerCallback caller, long pos) {
125042ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErik            MediaSession session = mMediaSession.get();
12518ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik            if (session != null) {
125221c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim                session.dispatchSeekTo(createRemoteUserInfo(packageName, pid, uid, caller), pos);
12538ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik            }
12548ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        }
12558ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik
12568ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        @Override
125721c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim        public void onRate(String packageName, int pid, int uid, ISessionControllerCallback caller,
125821c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim                Rating rating) {
125942ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErik            MediaSession session = mMediaSession.get();
12608ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik            if (session != null) {
126121c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim                session.dispatchRate(createRemoteUserInfo(packageName, pid, uid, caller), rating);
12628ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik            }
126301fe661ae5da3739215d93922412df4b24c859a2RoboErik        }
126401fe661ae5da3739215d93922412df4b24c859a2RoboErik
126507c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik        @Override
126621c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim        public void onCustomAction(String packageName, int pid, int uid,
126721c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim                ISessionControllerCallback caller, String action, Bundle args) {
1268f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal            MediaSession session = mMediaSession.get();
1269f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal            if (session != null) {
127021c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim                session.dispatchCustomAction(createRemoteUserInfo(packageName, pid, uid, caller),
127121c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim                        action, args);
1272f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal            }
1273f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal        }
1274f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal
1275f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal        @Override
127621c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim        public void onAdjustVolume(String packageName, int pid, int uid,
127721c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim                ISessionControllerCallback caller, int direction) {
12785d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik            MediaSession session = mMediaSession.get();
12795d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik            if (session != null) {
128021c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim                session.dispatchAdjustVolume(createRemoteUserInfo(packageName, pid, uid, caller),
128121c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim                        direction);
12825d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik            }
1283b69ffd4dc2c8fa85e0064151141ebeee90de471eRoboErik        }
1284b69ffd4dc2c8fa85e0064151141ebeee90de471eRoboErik
1285b69ffd4dc2c8fa85e0064151141ebeee90de471eRoboErik        @Override
128621c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim        public void onSetVolumeTo(String packageName, int pid, int uid,
128721c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim                ISessionControllerCallback caller, int value) {
12885d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik            MediaSession session = mMediaSession.get();
12895d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik            if (session != null) {
129021c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim                session.dispatchSetVolumeTo(createRemoteUserInfo(packageName, pid, uid, caller),
129121c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim                        value);
12925d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik            }
1293b69ffd4dc2c8fa85e0064151141ebeee90de471eRoboErik        }
129401fe661ae5da3739215d93922412df4b24c859a2RoboErik    }
129501fe661ae5da3739215d93922412df4b24c859a2RoboErik
1296f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal    /**
12973625bf72cb8bcf3c7f8f8cd8d708d7206824cc62RoboErik     * A single item that is part of the play queue. It contains a description
12983625bf72cb8bcf3c7f8f8cd8d708d7206824cc62RoboErik     * of the item and its id in the queue.
1299f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal     */
13003625bf72cb8bcf3c7f8f8cd8d708d7206824cc62RoboErik    public static final class QueueItem implements Parcelable {
1301f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal        /**
13023e5a34ea8e90e013c7edd39675746130a6eea954Sungsoo         * This id is reserved. No items can be explicitly assigned this id.
1303f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal         */
1304f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal        public static final int UNKNOWN_ID = -1;
1305f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal
13063625bf72cb8bcf3c7f8f8cd8d708d7206824cc62RoboErik        private final MediaDescription mDescription;
1307f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal        private final long mId;
1308f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal
1309f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal        /**
13103625bf72cb8bcf3c7f8f8cd8d708d7206824cc62RoboErik         * Create a new {@link MediaSession.QueueItem}.
1311f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal         *
13123625bf72cb8bcf3c7f8f8cd8d708d7206824cc62RoboErik         * @param description The {@link MediaDescription} for this item.
1313a66c40bf6e0fb79ead6d8a9fc29c5671fa7b1206RoboErik         * @param id An identifier for this item. It must be unique within the
13143625bf72cb8bcf3c7f8f8cd8d708d7206824cc62RoboErik         *            play queue and cannot be {@link #UNKNOWN_ID}.
1315f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal         */
13163625bf72cb8bcf3c7f8f8cd8d708d7206824cc62RoboErik        public QueueItem(MediaDescription description, long id) {
13173625bf72cb8bcf3c7f8f8cd8d708d7206824cc62RoboErik            if (description == null) {
13183625bf72cb8bcf3c7f8f8cd8d708d7206824cc62RoboErik                throw new IllegalArgumentException("Description cannot be null.");
13193625bf72cb8bcf3c7f8f8cd8d708d7206824cc62RoboErik            }
13203625bf72cb8bcf3c7f8f8cd8d708d7206824cc62RoboErik            if (id == UNKNOWN_ID) {
13213625bf72cb8bcf3c7f8f8cd8d708d7206824cc62RoboErik                throw new IllegalArgumentException("Id cannot be QueueItem.UNKNOWN_ID");
13223625bf72cb8bcf3c7f8f8cd8d708d7206824cc62RoboErik            }
13233625bf72cb8bcf3c7f8f8cd8d708d7206824cc62RoboErik            mDescription = description;
1324f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal            mId = id;
1325f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal        }
1326f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal
13273625bf72cb8bcf3c7f8f8cd8d708d7206824cc62RoboErik        private QueueItem(Parcel in) {
13283625bf72cb8bcf3c7f8f8cd8d708d7206824cc62RoboErik            mDescription = MediaDescription.CREATOR.createFromParcel(in);
1329f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal            mId = in.readLong();
1330f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal        }
1331f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal
1332f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal        /**
13333625bf72cb8bcf3c7f8f8cd8d708d7206824cc62RoboErik         * Get the description for this item.
1334f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal         */
13353625bf72cb8bcf3c7f8f8cd8d708d7206824cc62RoboErik        public MediaDescription getDescription() {
13363625bf72cb8bcf3c7f8f8cd8d708d7206824cc62RoboErik            return mDescription;
1337f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal        }
1338f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal
1339f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal        /**
13403625bf72cb8bcf3c7f8f8cd8d708d7206824cc62RoboErik         * Get the queue id for this item.
1341f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal         */
13423625bf72cb8bcf3c7f8f8cd8d708d7206824cc62RoboErik        public long getQueueId() {
1343f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal            return mId;
1344f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal        }
1345f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal
1346f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal        @Override
1347f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal        public void writeToParcel(Parcel dest, int flags) {
13483625bf72cb8bcf3c7f8f8cd8d708d7206824cc62RoboErik            mDescription.writeToParcel(dest, flags);
1349f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal            dest.writeLong(mId);
1350f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal        }
1351f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal
1352f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal        @Override
1353f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal        public int describeContents() {
1354f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal            return 0;
1355f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal        }
1356f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal
1357b1e344eaab519aa9bc9db20c891831dfe2bf92abHyundo Moon        public static final Creator<MediaSession.QueueItem> CREATOR =
1358b1e344eaab519aa9bc9db20c891831dfe2bf92abHyundo Moon                new Creator<MediaSession.QueueItem>() {
1359f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal
1360f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal            @Override
13613625bf72cb8bcf3c7f8f8cd8d708d7206824cc62RoboErik            public MediaSession.QueueItem createFromParcel(Parcel p) {
13623625bf72cb8bcf3c7f8f8cd8d708d7206824cc62RoboErik                return new MediaSession.QueueItem(p);
1363f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal            }
1364f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal
1365f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal            @Override
13663625bf72cb8bcf3c7f8f8cd8d708d7206824cc62RoboErik            public MediaSession.QueueItem[] newArray(int size) {
13673625bf72cb8bcf3c7f8f8cd8d708d7206824cc62RoboErik                return new MediaSession.QueueItem[size];
1368f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal            }
1369f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal        };
1370f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal
1371f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal        @Override
1372f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal        public String toString() {
13733625bf72cb8bcf3c7f8f8cd8d708d7206824cc62RoboErik            return "MediaSession.QueueItem {" +
13743625bf72cb8bcf3c7f8f8cd8d708d7206824cc62RoboErik                    "Description=" + mDescription +
13753625bf72cb8bcf3c7f8f8cd8d708d7206824cc62RoboErik                    ", Id=" + mId + " }";
1376f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal        }
13776edb68bea68d5f324384f3e9e411118eb8dfc781Ajay Panicker
13786edb68bea68d5f324384f3e9e411118eb8dfc781Ajay Panicker        @Override
13796edb68bea68d5f324384f3e9e411118eb8dfc781Ajay Panicker        public boolean equals(Object o) {
13806edb68bea68d5f324384f3e9e411118eb8dfc781Ajay Panicker            if (o == null) {
13816edb68bea68d5f324384f3e9e411118eb8dfc781Ajay Panicker                return false;
13826edb68bea68d5f324384f3e9e411118eb8dfc781Ajay Panicker            }
13836edb68bea68d5f324384f3e9e411118eb8dfc781Ajay Panicker
13846edb68bea68d5f324384f3e9e411118eb8dfc781Ajay Panicker            if (!(o instanceof QueueItem)) {
13856edb68bea68d5f324384f3e9e411118eb8dfc781Ajay Panicker                return false;
13866edb68bea68d5f324384f3e9e411118eb8dfc781Ajay Panicker            }
13876edb68bea68d5f324384f3e9e411118eb8dfc781Ajay Panicker
13886edb68bea68d5f324384f3e9e411118eb8dfc781Ajay Panicker            final QueueItem item = (QueueItem) o;
13896edb68bea68d5f324384f3e9e411118eb8dfc781Ajay Panicker            if (mId != item.mId) {
13906edb68bea68d5f324384f3e9e411118eb8dfc781Ajay Panicker                return false;
13916edb68bea68d5f324384f3e9e411118eb8dfc781Ajay Panicker            }
13926edb68bea68d5f324384f3e9e411118eb8dfc781Ajay Panicker
13936edb68bea68d5f324384f3e9e411118eb8dfc781Ajay Panicker            if (!Objects.equals(mDescription, item.mDescription)) {
13946edb68bea68d5f324384f3e9e411118eb8dfc781Ajay Panicker                return false;
13956edb68bea68d5f324384f3e9e411118eb8dfc781Ajay Panicker            }
13966edb68bea68d5f324384f3e9e411118eb8dfc781Ajay Panicker
13976edb68bea68d5f324384f3e9e411118eb8dfc781Ajay Panicker            return true;
13986edb68bea68d5f324384f3e9e411118eb8dfc781Ajay Panicker        }
1399f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal    }
1400f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal
14018ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik    private static final class Command {
14028ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        public final String command;
14038ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        public final Bundle extras;
14048ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        public final ResultReceiver stub;
14058ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik
14068ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        public Command(String command, Bundle extras, ResultReceiver stub) {
14078ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik            this.command = command;
14088ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik            this.extras = extras;
14098ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik            this.stub = stub;
14108ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        }
141101fe661ae5da3739215d93922412df4b24c859a2RoboErik    }
1412c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik
1413477d1197c3c25c01ace7ea4494437c23720a2eb3RoboErik    private class CallbackMessageHandler extends Handler {
141422188f118754c3b31c13d2f94daf718f111d92afDonghyun Cho        private static final int MSG_COMMAND = 1;
141522188f118754c3b31c13d2f94daf718f111d92afDonghyun Cho        private static final int MSG_MEDIA_BUTTON = 2;
141622188f118754c3b31c13d2f94daf718f111d92afDonghyun Cho        private static final int MSG_PREPARE = 3;
141722188f118754c3b31c13d2f94daf718f111d92afDonghyun Cho        private static final int MSG_PREPARE_MEDIA_ID = 4;
141822188f118754c3b31c13d2f94daf718f111d92afDonghyun Cho        private static final int MSG_PREPARE_SEARCH = 5;
141922188f118754c3b31c13d2f94daf718f111d92afDonghyun Cho        private static final int MSG_PREPARE_URI = 6;
142022188f118754c3b31c13d2f94daf718f111d92afDonghyun Cho        private static final int MSG_PLAY = 7;
142122188f118754c3b31c13d2f94daf718f111d92afDonghyun Cho        private static final int MSG_PLAY_MEDIA_ID = 8;
142222188f118754c3b31c13d2f94daf718f111d92afDonghyun Cho        private static final int MSG_PLAY_SEARCH = 9;
142322188f118754c3b31c13d2f94daf718f111d92afDonghyun Cho        private static final int MSG_PLAY_URI = 10;
142422188f118754c3b31c13d2f94daf718f111d92afDonghyun Cho        private static final int MSG_SKIP_TO_ITEM = 11;
142522188f118754c3b31c13d2f94daf718f111d92afDonghyun Cho        private static final int MSG_PAUSE = 12;
142622188f118754c3b31c13d2f94daf718f111d92afDonghyun Cho        private static final int MSG_STOP = 13;
142722188f118754c3b31c13d2f94daf718f111d92afDonghyun Cho        private static final int MSG_NEXT = 14;
142822188f118754c3b31c13d2f94daf718f111d92afDonghyun Cho        private static final int MSG_PREVIOUS = 15;
142922188f118754c3b31c13d2f94daf718f111d92afDonghyun Cho        private static final int MSG_FAST_FORWARD = 16;
143022188f118754c3b31c13d2f94daf718f111d92afDonghyun Cho        private static final int MSG_REWIND = 17;
143122188f118754c3b31c13d2f94daf718f111d92afDonghyun Cho        private static final int MSG_SEEK_TO = 18;
143222188f118754c3b31c13d2f94daf718f111d92afDonghyun Cho        private static final int MSG_RATE = 19;
14333e5a34ea8e90e013c7edd39675746130a6eea954Sungsoo        private static final int MSG_CUSTOM_ACTION = 20;
14343e5a34ea8e90e013c7edd39675746130a6eea954Sungsoo        private static final int MSG_ADJUST_VOLUME = 21;
14353e5a34ea8e90e013c7edd39675746130a6eea954Sungsoo        private static final int MSG_SET_VOLUME = 22;
143674d002be26ec9800cb494471f0773493bc83d8f7Jaewan Kim        private static final int MSG_PLAY_PAUSE_KEY_DOUBLE_TAP_TIMEOUT = 23;
1437c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik
1438477d1197c3c25c01ace7ea4494437c23720a2eb3RoboErik        private MediaSession.Callback mCallback;
143921c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim        private RemoteUserInfo mCurrentControllerInfo;
1440b1e344eaab519aa9bc9db20c891831dfe2bf92abHyundo Moon
1441477d1197c3c25c01ace7ea4494437c23720a2eb3RoboErik        public CallbackMessageHandler(Looper looper, MediaSession.Callback callback) {
1442477d1197c3c25c01ace7ea4494437c23720a2eb3RoboErik            super(looper, null, true);
1443477d1197c3c25c01ace7ea4494437c23720a2eb3RoboErik            mCallback = callback;
144474d002be26ec9800cb494471f0773493bc83d8f7Jaewan Kim            mCallback.mHandler = this;
1445c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik        }
1446c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik
144721c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim        public void post(RemoteUserInfo caller, int what, Object obj, Bundle data, long delayMs) {
144821c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim            Pair<RemoteUserInfo, Object> objWithCaller = Pair.create(caller, obj);
144921c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim            Message msg = obtainMessage(what, objWithCaller);
145077748b623c893f3c11714580d1a99fae934185ffJaewan Kim            msg.setData(data);
145121c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim            if (delayMs > 0) {
145221c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim                sendMessageDelayed(msg, delayMs);
145321c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim            } else {
145421c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim                sendMessage(msg);
145521c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim            }
145677748b623c893f3c11714580d1a99fae934185ffJaewan Kim        }
145777748b623c893f3c11714580d1a99fae934185ffJaewan Kim
1458c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik        @Override
1459c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik        public void handleMessage(Message msg) {
146021c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim            mCurrentControllerInfo = ((Pair<RemoteUserInfo, Object>) msg.obj).first;
1461b1e344eaab519aa9bc9db20c891831dfe2bf92abHyundo Moon
146221c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim            VolumeProvider vp;
146321c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim            Object obj = ((Pair<RemoteUserInfo, Object>) msg.obj).second;
1464b1e344eaab519aa9bc9db20c891831dfe2bf92abHyundo Moon
1465c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik            switch (msg.what) {
146622188f118754c3b31c13d2f94daf718f111d92afDonghyun Cho                case MSG_COMMAND:
146721c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim                    Command cmd = (Command) obj;
146822188f118754c3b31c13d2f94daf718f111d92afDonghyun Cho                    mCallback.onCommand(cmd.command, cmd.extras, cmd.stub);
146922188f118754c3b31c13d2f94daf718f111d92afDonghyun Cho                    break;
147022188f118754c3b31c13d2f94daf718f111d92afDonghyun Cho                case MSG_MEDIA_BUTTON:
147121c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim                    mCallback.onMediaButtonEvent((Intent) obj);
147222188f118754c3b31c13d2f94daf718f111d92afDonghyun Cho                    break;
147322188f118754c3b31c13d2f94daf718f111d92afDonghyun Cho                case MSG_PREPARE:
147422188f118754c3b31c13d2f94daf718f111d92afDonghyun Cho                    mCallback.onPrepare();
147522188f118754c3b31c13d2f94daf718f111d92afDonghyun Cho                    break;
147622188f118754c3b31c13d2f94daf718f111d92afDonghyun Cho                case MSG_PREPARE_MEDIA_ID:
147721c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim                    mCallback.onPrepareFromMediaId((String) obj, msg.getData());
147822188f118754c3b31c13d2f94daf718f111d92afDonghyun Cho                    break;
147922188f118754c3b31c13d2f94daf718f111d92afDonghyun Cho                case MSG_PREPARE_SEARCH:
148021c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim                    mCallback.onPrepareFromSearch((String) obj, msg.getData());
148122188f118754c3b31c13d2f94daf718f111d92afDonghyun Cho                    break;
148222188f118754c3b31c13d2f94daf718f111d92afDonghyun Cho                case MSG_PREPARE_URI:
148321c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim                    mCallback.onPrepareFromUri((Uri) obj, msg.getData());
148422188f118754c3b31c13d2f94daf718f111d92afDonghyun Cho                    break;
1485c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik                case MSG_PLAY:
1486c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik                    mCallback.onPlay();
1487c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik                    break;
14883625bf72cb8bcf3c7f8f8cd8d708d7206824cc62RoboErik                case MSG_PLAY_MEDIA_ID:
148921c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim                    mCallback.onPlayFromMediaId((String) obj, msg.getData());
1490f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal                    break;
1491f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal                case MSG_PLAY_SEARCH:
149221c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim                    mCallback.onPlayFromSearch((String) obj, msg.getData());
1493f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal                    break;
1494c2045470a343923b0d74ddbd6a6b80fcf6652d66P.Y. Laligand                case MSG_PLAY_URI:
149521c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim                    mCallback.onPlayFromUri((Uri) obj, msg.getData());
1496c2045470a343923b0d74ddbd6a6b80fcf6652d66P.Y. Laligand                    break;
1497a66c40bf6e0fb79ead6d8a9fc29c5671fa7b1206RoboErik                case MSG_SKIP_TO_ITEM:
149821c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim                    mCallback.onSkipToQueueItem((Long) obj);
149959759903a9696daefa817079c8432468ed398033RoboErik                    break;
1500c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik                case MSG_PAUSE:
1501c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik                    mCallback.onPause();
1502c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik                    break;
1503c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik                case MSG_STOP:
1504c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik                    mCallback.onStop();
1505c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik                    break;
1506c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik                case MSG_NEXT:
1507c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik                    mCallback.onSkipToNext();
1508c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik                    break;
1509c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik                case MSG_PREVIOUS:
1510c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik                    mCallback.onSkipToPrevious();
1511c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik                    break;
1512c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik                case MSG_FAST_FORWARD:
1513c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik                    mCallback.onFastForward();
1514c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik                    break;
1515c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik                case MSG_REWIND:
1516c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik                    mCallback.onRewind();
1517c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik                    break;
1518c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik                case MSG_SEEK_TO:
151921c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim                    mCallback.onSeekTo((Long) obj);
1520c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik                    break;
1521c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik                case MSG_RATE:
152221c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim                    mCallback.onSetRating((Rating) obj);
1523c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik                    break;
1524f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal                case MSG_CUSTOM_ACTION:
152521c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim                    mCallback.onCustomAction((String) obj, msg.getData());
1526f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal                    break;
1527563acea6665c45902bbc46db1a22c036344a818bRoboErik                case MSG_ADJUST_VOLUME:
1528563acea6665c45902bbc46db1a22c036344a818bRoboErik                    synchronized (mLock) {
1529563acea6665c45902bbc46db1a22c036344a818bRoboErik                        vp = mVolumeProvider;
1530563acea6665c45902bbc46db1a22c036344a818bRoboErik                    }
1531563acea6665c45902bbc46db1a22c036344a818bRoboErik                    if (vp != null) {
153221c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim                        vp.onAdjustVolume((int) obj);
1533563acea6665c45902bbc46db1a22c036344a818bRoboErik                    }
1534563acea6665c45902bbc46db1a22c036344a818bRoboErik                    break;
1535563acea6665c45902bbc46db1a22c036344a818bRoboErik                case MSG_SET_VOLUME:
1536563acea6665c45902bbc46db1a22c036344a818bRoboErik                    synchronized (mLock) {
1537563acea6665c45902bbc46db1a22c036344a818bRoboErik                        vp = mVolumeProvider;
1538563acea6665c45902bbc46db1a22c036344a818bRoboErik                    }
1539563acea6665c45902bbc46db1a22c036344a818bRoboErik                    if (vp != null) {
154021c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim                        vp.onSetVolumeTo((int) obj);
1541563acea6665c45902bbc46db1a22c036344a818bRoboErik                    }
1542563acea6665c45902bbc46db1a22c036344a818bRoboErik                    break;
154374d002be26ec9800cb494471f0773493bc83d8f7Jaewan Kim                case MSG_PLAY_PAUSE_KEY_DOUBLE_TAP_TIMEOUT:
154474d002be26ec9800cb494471f0773493bc83d8f7Jaewan Kim                    mCallback.handleMediaPlayPauseKeySingleTapIfPending();
154574d002be26ec9800cb494471f0773493bc83d8f7Jaewan Kim                    break;
1546c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik            }
154721c23e30b434ba23aa489f89f94a32b77c46e35aJaewan Kim            mCurrentControllerInfo = null;
1548c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik        }
1549c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik    }
155001fe661ae5da3739215d93922412df4b24c859a2RoboErik}
1551