124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown/*
324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown * Copyright (C) 2014 The Android Open Source Project
424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown *
524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown * Licensed under the Apache License, Version 2.0 (the "License");
624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown * you may not use this file except in compliance with the License.
724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown * You may obtain a copy of the License at
824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown *
924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown *      http://www.apache.org/licenses/LICENSE-2.0
1024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown *
1124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown * Unless required by applicable law or agreed to in writing, software
1224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown * distributed under the License is distributed on an "AS IS" BASIS,
1324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown * See the License for the specific language governing permissions and
1524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown * limitations under the License.
1624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown */
1724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
1824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brownpackage android.support.v4.media.session;
1924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
2085d539daa11f9f7bd61ecb8ebb4d43536c02a736RoboErikimport android.app.Activity;
2185d539daa11f9f7bd61ecb8ebb4d43536c02a736RoboErikimport android.app.PendingIntent;
225c9469e010106467791b47b0fa83efda84491a21RoboErikimport android.content.ComponentName;
2324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brownimport android.content.Context;
2424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brownimport android.content.Intent;
2524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brownimport android.media.AudioManager;
2624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brownimport android.os.Bundle;
2724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brownimport android.os.Handler;
28e49860b0f76d8336c1d41831ed370b0ff94278efRoboErikimport android.os.IBinder;
29e49860b0f76d8336c1d41831ed370b0ff94278efRoboErikimport android.os.Looper;
30e49860b0f76d8336c1d41831ed370b0ff94278efRoboErikimport android.os.Message;
3124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brownimport android.os.Parcel;
3224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brownimport android.os.Parcelable;
33e49860b0f76d8336c1d41831ed370b0ff94278efRoboErikimport android.os.RemoteCallbackList;
34e49860b0f76d8336c1d41831ed370b0ff94278efRoboErikimport android.os.RemoteException;
3524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brownimport android.os.ResultReceiver;
36e49860b0f76d8336c1d41831ed370b0ff94278efRoboErikimport android.os.SystemClock;
37ceb8bf5e5cce7a37736981e626c4be416378767bRoboErikimport android.support.v4.media.MediaDescriptionCompat;
3824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brownimport android.support.v4.media.MediaMetadataCompat;
3924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brownimport android.support.v4.media.RatingCompat;
4024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brownimport android.support.v4.media.VolumeProviderCompat;
4124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brownimport android.text.TextUtils;
42e49860b0f76d8336c1d41831ed370b0ff94278efRoboErikimport android.util.Log;
43e49860b0f76d8336c1d41831ed370b0ff94278efRoboErikimport android.view.KeyEvent;
4424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
45e49860b0f76d8336c1d41831ed370b0ff94278efRoboErikimport java.lang.ref.WeakReference;
46ceb8bf5e5cce7a37736981e626c4be416378767bRoboErikimport java.util.ArrayList;
47ceb8bf5e5cce7a37736981e626c4be416378767bRoboErikimport java.util.List;
48ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik
4924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown/**
5024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown * Allows interaction with media controllers, volume keys, media buttons, and
5124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown * transport controls.
5224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown * <p>
5324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown * A MediaSession should be created when an app wants to publish media playback
5424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown * information or handle media keys. In general an app only needs one session
5524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown * for all playback, though multiple sessions can be created to provide finer
5624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown * grain controls of media.
5724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown * <p>
5824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown * Once a session is created the owner of the session may pass its
5924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown * {@link #getSessionToken() session token} to other processes to allow them to
6024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown * create a {@link MediaControllerCompat} to interact with the session.
6124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown * <p>
6224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown * To receive commands, media keys, and other events a {@link Callback} must be
638af0092e2d7409e79779af396d63ca4146f1fb21RoboErik * set with {@link #setCallback(Callback)}.
6424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown * <p>
6524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown * When an app is finished performing playback it must call {@link #release()}
6624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown * to clean up the session and notify any controllers.
6724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown * <p>
685c9469e010106467791b47b0fa83efda84491a21RoboErik * MediaSessionCompat objects are not thread safe and all calls should be made
695c9469e010106467791b47b0fa83efda84491a21RoboErik * from the same thread.
7024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown * <p>
718af0092e2d7409e79779af396d63ca4146f1fb21RoboErik * This is a helper for accessing features in
728af0092e2d7409e79779af396d63ca4146f1fb21RoboErik * {@link android.media.session.MediaSession} introduced after API level 4 in a
738af0092e2d7409e79779af396d63ca4146f1fb21RoboErik * backwards compatible fashion.
7424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown */
7524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brownpublic class MediaSessionCompat {
7624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    private final MediaSessionImpl mImpl;
77ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik    private final MediaControllerCompat mController;
785c9469e010106467791b47b0fa83efda84491a21RoboErik    private final ArrayList<OnActiveChangeListener>
795c9469e010106467791b47b0fa83efda84491a21RoboErik            mActiveListeners = new ArrayList<OnActiveChangeListener>();
8024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
8124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    /**
8224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * Set this flag on the session to indicate that it can handle media button
8324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * events.
8424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     */
8524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    public static final int FLAG_HANDLES_MEDIA_BUTTONS = 1 << 0;
8624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
8724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    /**
8824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * Set this flag on the session to indicate that it handles transport
898af0092e2d7409e79779af396d63ca4146f1fb21RoboErik     * control commands through its {@link Callback}.
9024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     */
9124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    public static final int FLAG_HANDLES_TRANSPORT_CONTROLS = 1 << 1;
9224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
9324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    /**
9424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * Creates a new session.
9524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     *
9624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * @param context The context.
9724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * @param tag A short name for debugging purposes.
985c9469e010106467791b47b0fa83efda84491a21RoboErik     * @param mediaButtonEventReceiver The component name for your receiver.
995c9469e010106467791b47b0fa83efda84491a21RoboErik     *            This must be non-null to support platform versions earlier
1005c9469e010106467791b47b0fa83efda84491a21RoboErik     *            than {@link android.os.Build.VERSION_CODES#LOLLIPOP}.
1015c9469e010106467791b47b0fa83efda84491a21RoboErik     * @param mbrIntent The PendingIntent for your receiver component that
1025c9469e010106467791b47b0fa83efda84491a21RoboErik     *            handles media button events. This is optional and will be used
1035c9469e010106467791b47b0fa83efda84491a21RoboErik     *            on {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2} and
1045c9469e010106467791b47b0fa83efda84491a21RoboErik     *            later instead of the component name.
10524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     */
1065c9469e010106467791b47b0fa83efda84491a21RoboErik    public MediaSessionCompat(Context context, String tag, ComponentName mediaButtonEventReceiver,
1075c9469e010106467791b47b0fa83efda84491a21RoboErik            PendingIntent mbrIntent) {
10824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        if (context == null) {
10924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            throw new IllegalArgumentException("context must not be null");
11024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
11124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        if (TextUtils.isEmpty(tag)) {
11224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            throw new IllegalArgumentException("tag must not be null or empty");
11324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
11424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
11524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        if (android.os.Build.VERSION.SDK_INT >= 21) {
11624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            mImpl = new MediaSessionImplApi21(context, tag);
1175c9469e010106467791b47b0fa83efda84491a21RoboErik            mImpl.setMediaButtonReceiver(mbrIntent);
11824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        } else {
119e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            mImpl = new MediaSessionImplBase(context, tag, mediaButtonEventReceiver, mbrIntent);
12024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
121ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik        mController = new MediaControllerCompat(context, this);
12224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    }
12324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
124ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik    private MediaSessionCompat(Context context, MediaSessionImpl impl) {
125bbcdf78e350d58ecd6baa75e282d4908d3129fe2RoboErik        mImpl = impl;
126ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik        mController = new MediaControllerCompat(context, this);
127bbcdf78e350d58ecd6baa75e282d4908d3129fe2RoboErik    }
128bbcdf78e350d58ecd6baa75e282d4908d3129fe2RoboErik
12924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    /**
13024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * Add a callback to receive updates on for the MediaSession. This includes
13124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * media button and volume events. The caller's thread will be used to post
13224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * events.
13324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     *
13424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * @param callback The callback object
13524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     */
1368af0092e2d7409e79779af396d63ca4146f1fb21RoboErik    public void setCallback(Callback callback) {
1378af0092e2d7409e79779af396d63ca4146f1fb21RoboErik        setCallback(callback, null);
13824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    }
13924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
14024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    /**
1418af0092e2d7409e79779af396d63ca4146f1fb21RoboErik     * Set the callback to receive updates for the MediaSession. This includes
1428af0092e2d7409e79779af396d63ca4146f1fb21RoboErik     * media button and volume events. Set the callback to null to stop
1438af0092e2d7409e79779af396d63ca4146f1fb21RoboErik     * receiving events.
14424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     *
14524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * @param callback The callback to receive updates on.
14624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * @param handler The handler that events should be posted on.
14724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     */
1488af0092e2d7409e79779af396d63ca4146f1fb21RoboErik    public void setCallback(Callback callback, Handler handler) {
1498af0092e2d7409e79779af396d63ca4146f1fb21RoboErik        mImpl.setCallback(callback, handler != null ? handler : new Handler());
15024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    }
15124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
15224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    /**
153ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik     * Set an intent for launching UI for this Session. This can be used as a
154ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik     * quick link to an ongoing media screen. The intent should be for an
155ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik     * activity that may be started using
156ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik     * {@link Activity#startActivity(Intent)}.
157ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik     *
158ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik     * @param pi The intent to launch to show UI for this Session.
159ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik     */
160ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik    public void setSessionActivity(PendingIntent pi) {
161ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik        mImpl.setSessionActivity(pi);
162ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik    }
163ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik
164ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik    /**
165ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik     * Set a pending intent for your media button receiver to allow restarting
166ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik     * playback after the session has been stopped. If your app is started in
167ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik     * this way an {@link Intent#ACTION_MEDIA_BUTTON} intent will be sent via
168ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik     * the pending intent.
169ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik     * <p>
1705c9469e010106467791b47b0fa83efda84491a21RoboErik     * This method will only work on
1715c9469e010106467791b47b0fa83efda84491a21RoboErik     * {@link android.os.Build.VERSION_CODES#LOLLIPOP} and later. Earlier
1725c9469e010106467791b47b0fa83efda84491a21RoboErik     * platform versions must include the media button receiver in the
1735c9469e010106467791b47b0fa83efda84491a21RoboErik     * constructor.
174ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik     *
175ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik     * @param mbr The {@link PendingIntent} to send the media button event to.
176ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik     */
177ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik    public void setMediaButtonReceiver(PendingIntent mbr) {
178ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik        mImpl.setMediaButtonReceiver(mbr);
179ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik    }
180ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik
181ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik    /**
18224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * Set any flags for the session.
18324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     *
18424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * @param flags The flags to set for this session.
18524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     */
18624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    public void setFlags(int flags) {
18724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        mImpl.setFlags(flags);
18824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    }
18924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
19024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    /**
19124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * Set the stream this session is playing on. This will affect the system's
19224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * volume handling for this session. If {@link #setPlaybackToRemote} was
19324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * previously called it will stop receiving volume commands and the system
19424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * will begin sending volume changes to the appropriate stream.
19524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * <p>
19624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * By default sessions are on {@link AudioManager#STREAM_MUSIC}.
19724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     *
19824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * @param stream The {@link AudioManager} stream this session is playing on.
19924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     */
20024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    public void setPlaybackToLocal(int stream) {
20124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        mImpl.setPlaybackToLocal(stream);
20224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    }
20324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
20424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    /**
20524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * Configure this session to use remote volume handling. This must be called
20624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * to receive volume button events, otherwise the system will adjust the
20724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * current stream volume for this session. If {@link #setPlaybackToLocal}
20824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * was previously called that stream will stop receiving volume changes for
20924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * this session.
210e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik     * <p>
211e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik     * On platforms earlier than {@link android.os.Build.VERSION_CODES#LOLLIPOP}
212e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik     * this will only allow an app to handle volume commands sent directly to
213e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik     * the session by a {@link MediaControllerCompat}. System routing of volume
214e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik     * keys will not use the volume provider.
21524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     *
21624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * @param volumeProvider The provider that will handle volume changes. May
21724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     *            not be null.
21824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     */
21924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    public void setPlaybackToRemote(VolumeProviderCompat volumeProvider) {
22024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        if (volumeProvider == null) {
22124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            throw new IllegalArgumentException("volumeProvider may not be null!");
22224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
22324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        mImpl.setPlaybackToRemote(volumeProvider);
22424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    }
22524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
22624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    /**
22724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * Set if this session is currently active and ready to receive commands. If
22824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * set to false your session's controller may not be discoverable. You must
22924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * set the session to active before it can start receiving media button
23024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * events or transport commands.
231ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik     * <p>
232ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik     * On platforms earlier than
233ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik     * {@link android.os.Build.VERSION_CODES#LOLLIPOP},
234ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik     * {@link #setMediaButtonReceiver(PendingIntent)} must be called before
235ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik     * setting this to true.
23624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     *
23724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * @param active Whether this session is active or not.
23824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     */
23924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    public void setActive(boolean active) {
24024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        mImpl.setActive(active);
2415c9469e010106467791b47b0fa83efda84491a21RoboErik        for (OnActiveChangeListener listener : mActiveListeners) {
2425c9469e010106467791b47b0fa83efda84491a21RoboErik            listener.onActiveChanged();
2435c9469e010106467791b47b0fa83efda84491a21RoboErik        }
24424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    }
24524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
24624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    /**
24724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * Get the current active state of this session.
24824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     *
24924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * @return True if the session is active, false otherwise.
25024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     */
25124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    public boolean isActive() {
25224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        return mImpl.isActive();
25324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    }
25424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
25524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    /**
25624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * Send a proprietary event to all MediaControllers listening to this
25724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * Session. It's up to the Controller/Session owner to determine the meaning
25824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * of any events.
25924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     *
26024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * @param event The name of the event to send
26124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * @param extras Any extras included with the event
26224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     */
26324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    public void sendSessionEvent(String event, Bundle extras) {
26424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        if (TextUtils.isEmpty(event)) {
26524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            throw new IllegalArgumentException("event cannot be null or empty");
26624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
26724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        mImpl.sendSessionEvent(event, extras);
26824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    }
26924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
27024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    /**
27124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * This must be called when an app has finished performing playback. If
27224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * playback is expected to start again shortly the session can be left open,
27324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * but it must be released if your activity or service is being destroyed.
27424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     */
27524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    public void release() {
27624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        mImpl.release();
27724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    }
27824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
27924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    /**
28024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * Retrieve a token object that can be used by apps to create a
281e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik     * {@link MediaControllerCompat} for interacting with this session. The
282e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik     * owner of the session is responsible for deciding how to distribute these
283e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik     * tokens.
284e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik     * <p>
285e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik     * On platform versions before
286e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik     * {@link android.os.Build.VERSION_CODES#LOLLIPOP} this token may only be
287e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik     * used within your app as there is no way to guarantee other apps are using
288e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik     * the same version of the support library.
28924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     *
290e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik     * @return A token that can be used to create a media controller for this
29124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     *         session.
29224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     */
29324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    public Token getSessionToken() {
29424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        return mImpl.getSessionToken();
29524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    }
29624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
29724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    /**
298ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik     * Get a controller for this session. This is a convenience method to avoid
299ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik     * having to cache your own controller in process.
300ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik     *
301ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik     * @return A controller for this session.
302ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik     */
303ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik    public MediaControllerCompat getController() {
304ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik        return mController;
305ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik    }
306ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik
307ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik    /**
30824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * Update the current playback state.
30924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     *
31024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * @param state The current state of playback
31124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     */
31224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    public void setPlaybackState(PlaybackStateCompat state) {
31324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        mImpl.setPlaybackState(state);
31424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    }
31524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
31624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    /**
31724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * Update the current metadata. New metadata can be created using
31824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * {@link android.media.MediaMetadata.Builder}.
31924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     *
32024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * @param metadata The new metadata
32124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     */
32224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    public void setMetadata(MediaMetadataCompat metadata) {
32324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        mImpl.setMetadata(metadata);
32424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    }
32524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
32624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    /**
327ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik     * Update the list of items in the play queue. It is an ordered list and
328ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik     * should contain the current item, and previous or upcoming items if they
329ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik     * exist. Specify null if there is no current play queue.
330ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik     * <p>
331ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik     * The queue should be of reasonable size. If the play queue is unbounded
332ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik     * within your app, it is better to send a reasonable amount in a sliding
333ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik     * window instead.
33485d539daa11f9f7bd61ecb8ebb4d43536c02a736RoboErik     *
335ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik     * @param queue A list of items in the play queue.
33685d539daa11f9f7bd61ecb8ebb4d43536c02a736RoboErik     */
337ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik    public void setQueue(List<QueueItem> queue) {
338ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik        mImpl.setQueue(queue);
339ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik    }
340ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik
341ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik    /**
342ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik     * Set the title of the play queue. The UI should display this title along
343ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik     * with the play queue itself. e.g. "Play Queue", "Now Playing", or an album
344ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik     * name.
345ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik     *
346ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik     * @param title The title of the play queue.
347ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik     */
348ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik    public void setQueueTitle(CharSequence title) {
349ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik        mImpl.setQueueTitle(title);
350ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik    }
351ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik
352ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik    /**
353ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik     * Set the style of rating used by this session. Apps trying to set the
354ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik     * rating should use this style. Must be one of the following:
355ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik     * <ul>
356ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik     * <li>{@link RatingCompat#RATING_NONE}</li>
357ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik     * <li>{@link RatingCompat#RATING_3_STARS}</li>
358ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik     * <li>{@link RatingCompat#RATING_4_STARS}</li>
359ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik     * <li>{@link RatingCompat#RATING_5_STARS}</li>
360ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik     * <li>{@link RatingCompat#RATING_HEART}</li>
361ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik     * <li>{@link RatingCompat#RATING_PERCENTAGE}</li>
362ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik     * <li>{@link RatingCompat#RATING_THUMB_UP_DOWN}</li>
363ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik     * </ul>
364ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik     */
365ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik    public void setRatingType(int type) {
366ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik        mImpl.setRatingType(type);
367ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik    }
368ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik
369ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik    /**
370ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik     * Set some extras that can be associated with the
371ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik     * {@link MediaSessionCompat}. No assumptions should be made as to how a
372ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik     * {@link MediaControllerCompat} will handle these extras. Keys should be
373ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik     * fully qualified (e.g. com.example.MY_EXTRA) to avoid conflicts.
374ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik     *
375ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik     * @param extras The extras associated with the session.
376ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik     */
377ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik    public void setExtras(Bundle extras) {
378ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik        mImpl.setExtras(extras);
37985d539daa11f9f7bd61ecb8ebb4d43536c02a736RoboErik    }
38085d539daa11f9f7bd61ecb8ebb4d43536c02a736RoboErik
38185d539daa11f9f7bd61ecb8ebb4d43536c02a736RoboErik    /**
38285d539daa11f9f7bd61ecb8ebb4d43536c02a736RoboErik     * Gets the underlying framework {@link android.media.session.MediaSession}
38385d539daa11f9f7bd61ecb8ebb4d43536c02a736RoboErik     * object.
38424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * <p>
38524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * This method is only supported on API 21+.
38624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * </p>
38724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     *
38824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * @return The underlying {@link android.media.session.MediaSession} object,
38985d539daa11f9f7bd61ecb8ebb4d43536c02a736RoboErik     *         or null if none.
39024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     */
39124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    public Object getMediaSession() {
39224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        return mImpl.getMediaSession();
39324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    }
39424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
39524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    /**
3965c9469e010106467791b47b0fa83efda84491a21RoboErik     * Gets the underlying framework {@link android.media.RemoteControlClient}
3975c9469e010106467791b47b0fa83efda84491a21RoboErik     * object.
3985c9469e010106467791b47b0fa83efda84491a21RoboErik     * <p>
3995c9469e010106467791b47b0fa83efda84491a21RoboErik     * This method is only supported on APIs 14-20. On API 21+
4005c9469e010106467791b47b0fa83efda84491a21RoboErik     * {@link #getMediaSession()} should be used instead.
4015c9469e010106467791b47b0fa83efda84491a21RoboErik     *
4025c9469e010106467791b47b0fa83efda84491a21RoboErik     * @return The underlying {@link android.media.RemoteControlClient} object,
4035c9469e010106467791b47b0fa83efda84491a21RoboErik     *         or null if none.
4045c9469e010106467791b47b0fa83efda84491a21RoboErik     */
4055c9469e010106467791b47b0fa83efda84491a21RoboErik    public Object getRemoteControlClient() {
4065c9469e010106467791b47b0fa83efda84491a21RoboErik        return mImpl.getRemoteControlClient();
4075c9469e010106467791b47b0fa83efda84491a21RoboErik    }
4085c9469e010106467791b47b0fa83efda84491a21RoboErik
4095c9469e010106467791b47b0fa83efda84491a21RoboErik    /**
4105c9469e010106467791b47b0fa83efda84491a21RoboErik     * Adds a listener to be notified when the active status of this session
4115c9469e010106467791b47b0fa83efda84491a21RoboErik     * changes. This is primarily used by the support library and should not be
4125c9469e010106467791b47b0fa83efda84491a21RoboErik     * needed by apps.
4135c9469e010106467791b47b0fa83efda84491a21RoboErik     *
4145c9469e010106467791b47b0fa83efda84491a21RoboErik     * @param listener The listener to add.
4155c9469e010106467791b47b0fa83efda84491a21RoboErik     */
4165c9469e010106467791b47b0fa83efda84491a21RoboErik    public void addOnActiveChangeListener(OnActiveChangeListener listener) {
4175c9469e010106467791b47b0fa83efda84491a21RoboErik        if (listener == null) {
4185c9469e010106467791b47b0fa83efda84491a21RoboErik            throw new IllegalArgumentException("Listener may not be null");
4195c9469e010106467791b47b0fa83efda84491a21RoboErik        }
4205c9469e010106467791b47b0fa83efda84491a21RoboErik        mActiveListeners.add(listener);
4215c9469e010106467791b47b0fa83efda84491a21RoboErik    }
4225c9469e010106467791b47b0fa83efda84491a21RoboErik
4235c9469e010106467791b47b0fa83efda84491a21RoboErik    /**
4245c9469e010106467791b47b0fa83efda84491a21RoboErik     * Stops the listener from being notified when the active status of this
4255c9469e010106467791b47b0fa83efda84491a21RoboErik     * session changes.
4265c9469e010106467791b47b0fa83efda84491a21RoboErik     *
4275c9469e010106467791b47b0fa83efda84491a21RoboErik     * @param listener The listener to remove.
4285c9469e010106467791b47b0fa83efda84491a21RoboErik     */
4295c9469e010106467791b47b0fa83efda84491a21RoboErik    public void removeOnActiveChangeListener(OnActiveChangeListener listener) {
4305c9469e010106467791b47b0fa83efda84491a21RoboErik        if (listener == null) {
4315c9469e010106467791b47b0fa83efda84491a21RoboErik            throw new IllegalArgumentException("Listener may not be null");
4325c9469e010106467791b47b0fa83efda84491a21RoboErik        }
4335c9469e010106467791b47b0fa83efda84491a21RoboErik        mActiveListeners.remove(listener);
4345c9469e010106467791b47b0fa83efda84491a21RoboErik    }
4355c9469e010106467791b47b0fa83efda84491a21RoboErik
4365c9469e010106467791b47b0fa83efda84491a21RoboErik    /**
437bbcdf78e350d58ecd6baa75e282d4908d3129fe2RoboErik     * Obtain a compat wrapper for an existing MediaSession.
438bbcdf78e350d58ecd6baa75e282d4908d3129fe2RoboErik     *
439bbcdf78e350d58ecd6baa75e282d4908d3129fe2RoboErik     * @param mediaSession The {@link android.media.session.MediaSession} to
440bbcdf78e350d58ecd6baa75e282d4908d3129fe2RoboErik     *            wrap.
441bbcdf78e350d58ecd6baa75e282d4908d3129fe2RoboErik     * @return A compat wrapper for the provided session.
442bbcdf78e350d58ecd6baa75e282d4908d3129fe2RoboErik     */
443ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik    public static MediaSessionCompat obtain(Context context, Object mediaSession) {
444ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik        return new MediaSessionCompat(context, new MediaSessionImplApi21(mediaSession));
445bbcdf78e350d58ecd6baa75e282d4908d3129fe2RoboErik    }
446bbcdf78e350d58ecd6baa75e282d4908d3129fe2RoboErik
447bbcdf78e350d58ecd6baa75e282d4908d3129fe2RoboErik    /**
4488af0092e2d7409e79779af396d63ca4146f1fb21RoboErik     * Receives transport controls, media buttons, and commands from controllers
4498af0092e2d7409e79779af396d63ca4146f1fb21RoboErik     * and the system. The callback may be set using {@link #setCallback}.
45024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     */
45124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    public abstract static class Callback {
45224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        final Object mCallbackObj;
45324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
45424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public Callback() {
45524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            if (android.os.Build.VERSION.SDK_INT >= 21) {
45624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown                mCallbackObj = MediaSessionCompatApi21.createCallback(new StubApi21());
45724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            } else {
45824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown                mCallbackObj = null;
45924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            }
46024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
46124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
46224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        /**
46324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * Called when a controller has sent a custom command to this session.
46424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * The owner of the session may handle custom commands but is not
46524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * required to.
46624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         *
46724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * @param command The command name.
46824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * @param extras Optional parameters for the command, may be null.
46924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * @param cb A result receiver to which a result may be sent by the command, may be null.
47024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         */
471b530c89bba371d2d575f10480b2e90914b0d3f3fGabriel Peal        public void onCommand(String command, Bundle extras, ResultReceiver cb) {
47224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
47324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
4748af0092e2d7409e79779af396d63ca4146f1fb21RoboErik        /**
4758af0092e2d7409e79779af396d63ca4146f1fb21RoboErik         * Override to handle media button events.
4768af0092e2d7409e79779af396d63ca4146f1fb21RoboErik         *
4778af0092e2d7409e79779af396d63ca4146f1fb21RoboErik         * @param mediaButtonEvent The media button event intent.
4788af0092e2d7409e79779af396d63ca4146f1fb21RoboErik         * @return True if the event was handled, false otherwise.
4798af0092e2d7409e79779af396d63ca4146f1fb21RoboErik         */
4808af0092e2d7409e79779af396d63ca4146f1fb21RoboErik        public boolean onMediaButtonEvent(Intent mediaButtonEvent) {
4818af0092e2d7409e79779af396d63ca4146f1fb21RoboErik            return false;
48224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
48324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
48424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        /**
48524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * Override to handle requests to begin playback.
48624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         */
48724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public void onPlay() {
48824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
48924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
49024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        /**
491e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik         * Override to handle requests to play a specific mediaId that was
492e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik         * provided by your app.
493e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik         */
494e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        public void onPlayFromMediaId(String mediaId, Bundle extras) {
495e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        }
496e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
497e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        /**
498e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik         * Override to handle requests to begin playback from a search query. An
499e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik         * empty query indicates that the app may play any music. The
500e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik         * implementation should attempt to make a smart choice about what to
501e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik         * play.
502e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik         */
503e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        public void onPlayFromSearch(String query, Bundle extras) {
504e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        }
505e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
506e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        /**
507e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik         * Override to handle requests to play an item with a given id from the
508e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik         * play queue.
509e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik         */
510e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        public void onSkipToQueueItem(long id) {
511e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        }
512e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
513e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        /**
51424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * Override to handle requests to pause playback.
51524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         */
51624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public void onPause() {
51724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
51824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
51924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        /**
52024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * Override to handle requests to skip to the next media item.
52124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         */
52224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public void onSkipToNext() {
52324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
52424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
52524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        /**
52624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * Override to handle requests to skip to the previous media item.
52724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         */
52824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public void onSkipToPrevious() {
52924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
53024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
53124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        /**
53224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * Override to handle requests to fast forward.
53324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         */
53424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public void onFastForward() {
53524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
53624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
53724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        /**
53824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * Override to handle requests to rewind.
53924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         */
54024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public void onRewind() {
54124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
54224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
54324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        /**
54424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * Override to handle requests to stop playback.
54524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         */
54624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public void onStop() {
54724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
54824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
54924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        /**
55024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * Override to handle requests to seek to a specific position in ms.
55124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         *
55224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * @param pos New position to move to, in milliseconds.
55324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         */
55424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public void onSeekTo(long pos) {
55524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
55624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
55724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        /**
55824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * Override to handle the item being rated.
55924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         *
56024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * @param rating
56124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         */
56224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public void onSetRating(RatingCompat rating) {
56324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
56424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
565e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        /**
566e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik         * Called when a {@link MediaControllerCompat} wants a
567e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik         * {@link PlaybackStateCompat.CustomAction} to be performed.
568e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik         *
569e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik         * @param action The action that was originally sent in the
570e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik         *            {@link PlaybackStateCompat.CustomAction}.
571e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik         * @param extras Optional extras specified by the
572e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik         *            {@link MediaControllerCompat}.
573e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik         */
574e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        public void onCustomAction(String action, Bundle extras) {
575e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        }
576e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
5778af0092e2d7409e79779af396d63ca4146f1fb21RoboErik        private class StubApi21 implements MediaSessionCompatApi21.Callback {
5788af0092e2d7409e79779af396d63ca4146f1fb21RoboErik
5798af0092e2d7409e79779af396d63ca4146f1fb21RoboErik            @Override
5808af0092e2d7409e79779af396d63ca4146f1fb21RoboErik            public void onCommand(String command, Bundle extras, ResultReceiver cb) {
5818af0092e2d7409e79779af396d63ca4146f1fb21RoboErik                Callback.this.onCommand(command, extras, cb);
5828af0092e2d7409e79779af396d63ca4146f1fb21RoboErik            }
5838af0092e2d7409e79779af396d63ca4146f1fb21RoboErik
5848af0092e2d7409e79779af396d63ca4146f1fb21RoboErik            @Override
5858af0092e2d7409e79779af396d63ca4146f1fb21RoboErik            public boolean onMediaButtonEvent(Intent mediaButtonIntent) {
5868af0092e2d7409e79779af396d63ca4146f1fb21RoboErik                return Callback.this.onMediaButtonEvent(mediaButtonIntent);
5878af0092e2d7409e79779af396d63ca4146f1fb21RoboErik            }
5888af0092e2d7409e79779af396d63ca4146f1fb21RoboErik
58924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            @Override
59024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            public void onPlay() {
5918af0092e2d7409e79779af396d63ca4146f1fb21RoboErik                Callback.this.onPlay();
59224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            }
59324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
59424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            @Override
595e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            public void onPlayFromMediaId(String mediaId, Bundle extras) {
596e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                Callback.this.onPlayFromMediaId(mediaId, extras);
597e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
598e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
599e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            @Override
600e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            public void onPlayFromSearch(String search, Bundle extras) {
601e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                Callback.this.onPlayFromSearch(search, extras);
602e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
603e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
604e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            @Override
605e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            public void onSkipToQueueItem(long id) {
606e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                Callback.this.onSkipToQueueItem(id);
607e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
608e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
609e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            @Override
61024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            public void onPause() {
6118af0092e2d7409e79779af396d63ca4146f1fb21RoboErik                Callback.this.onPause();
61224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            }
61324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
61424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            @Override
61524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            public void onSkipToNext() {
6168af0092e2d7409e79779af396d63ca4146f1fb21RoboErik                Callback.this.onSkipToNext();
61724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            }
61824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
61924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            @Override
62024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            public void onSkipToPrevious() {
6218af0092e2d7409e79779af396d63ca4146f1fb21RoboErik                Callback.this.onSkipToPrevious();
62224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            }
62324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
62424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            @Override
62524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            public void onFastForward() {
6268af0092e2d7409e79779af396d63ca4146f1fb21RoboErik                Callback.this.onFastForward();
62724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            }
62824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
62924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            @Override
63024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            public void onRewind() {
6318af0092e2d7409e79779af396d63ca4146f1fb21RoboErik                Callback.this.onRewind();
63224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            }
63324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
63424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            @Override
63524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            public void onStop() {
6368af0092e2d7409e79779af396d63ca4146f1fb21RoboErik                Callback.this.onStop();
63724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            }
63824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
63924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            @Override
64024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            public void onSeekTo(long pos) {
6418af0092e2d7409e79779af396d63ca4146f1fb21RoboErik                Callback.this.onSeekTo(pos);
64224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            }
64324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
64424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            @Override
64524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            public void onSetRating(Object ratingObj) {
6468af0092e2d7409e79779af396d63ca4146f1fb21RoboErik                Callback.this.onSetRating(RatingCompat.fromRating(ratingObj));
64724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            }
648e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
649e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            @Override
650e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            public void onCustomAction(String action, Bundle extras) {
651e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                Callback.this.onCustomAction(action, extras);
652e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
65324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
65424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    }
65524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
65624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    /**
65724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * Represents an ongoing session. This may be passed to apps by the session
65824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * owner to allow them to create a {@link MediaControllerCompat} to communicate with
65924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * the session.
66024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     */
66124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    public static final class Token implements Parcelable {
662e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        private final Object mInner;
66324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
664e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        Token(Object inner) {
66524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            mInner = inner;
66624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
66724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
668ae70d8d953ef632acb9f176609a1f75bd948d101RoboErik        /**
669ae70d8d953ef632acb9f176609a1f75bd948d101RoboErik         * Creates a compat Token from a framework
670ae70d8d953ef632acb9f176609a1f75bd948d101RoboErik         * {@link android.media.session.MediaSession.Token} object.
671ae70d8d953ef632acb9f176609a1f75bd948d101RoboErik         * <p>
672ae70d8d953ef632acb9f176609a1f75bd948d101RoboErik         * This method is only supported on
673ae70d8d953ef632acb9f176609a1f75bd948d101RoboErik         * {@link android.os.Build.VERSION_CODES#LOLLIPOP} and later.
674ae70d8d953ef632acb9f176609a1f75bd948d101RoboErik         * </p>
675ae70d8d953ef632acb9f176609a1f75bd948d101RoboErik         *
676ae70d8d953ef632acb9f176609a1f75bd948d101RoboErik         * @param token The framework token object.
677ae70d8d953ef632acb9f176609a1f75bd948d101RoboErik         * @return A compat Token for use with {@link MediaControllerCompat}.
678ae70d8d953ef632acb9f176609a1f75bd948d101RoboErik         */
6794e3b8470fa30cba04e2fb6b95516cff8f3e1e499RoboErik        public static Token fromToken(Object token) {
680ae70d8d953ef632acb9f176609a1f75bd948d101RoboErik            if (token == null || android.os.Build.VERSION.SDK_INT < 21) {
681ae70d8d953ef632acb9f176609a1f75bd948d101RoboErik                return null;
682ae70d8d953ef632acb9f176609a1f75bd948d101RoboErik            }
683e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            return new Token(MediaSessionCompatApi21.verifyToken(token));
684ae70d8d953ef632acb9f176609a1f75bd948d101RoboErik        }
685ae70d8d953ef632acb9f176609a1f75bd948d101RoboErik
68624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        @Override
68724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public int describeContents() {
688e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            return 0;
68924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
69024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
69124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        @Override
69224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public void writeToParcel(Parcel dest, int flags) {
693e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            if (android.os.Build.VERSION.SDK_INT >= 21) {
694e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                dest.writeParcelable((Parcelable) mInner, flags);
695e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            } else {
696e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                dest.writeStrongBinder((IBinder) mInner);
697e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
69824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
69924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
70024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        /**
7018ea3b7e9bae080d5ab65a150e952c87db70cc3a3Jeff Brown         * Gets the underlying framework {@link android.media.session.MediaSession.Token} object.
70224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * <p>
70324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * This method is only supported on API 21+.
70424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * </p>
70524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         *
7068ea3b7e9bae080d5ab65a150e952c87db70cc3a3Jeff Brown         * @return The underlying {@link android.media.session.MediaSession.Token} object,
70724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * or null if none.
70824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         */
70924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public Object getToken() {
71024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            return mInner;
71124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
71224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
71324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public static final Parcelable.Creator<Token> CREATOR
71424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown                = new Parcelable.Creator<Token>() {
71524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            @Override
71624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            public Token createFromParcel(Parcel in) {
717e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                Object inner;
718e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                if (android.os.Build.VERSION.SDK_INT >= 21) {
719e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                    inner = in.readParcelable(null);
720e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                } else {
721e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                    inner = in.readStrongBinder();
722e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                }
723e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                return new Token(inner);
72424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            }
72524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
72624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            @Override
72724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            public Token[] newArray(int size) {
72824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown                return new Token[size];
72924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            }
73024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        };
73124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    }
73224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
733ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik    /**
734ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik     * A single item that is part of the play queue. It contains a description
735ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik     * of the item and its id in the queue.
736ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik     */
737ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik    public static final class QueueItem implements Parcelable {
738ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik        /**
739ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik         * This id is reserved. No items can be explicitly asigned this id.
740ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik         */
741ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik        public static final int UNKNOWN_ID = -1;
742ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik
743ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik        private final MediaDescriptionCompat mDescription;
744ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik        private final long mId;
745ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik
746ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik        private Object mItem;
747ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik
748ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik        /**
749ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik         * Create a new {@link MediaSessionCompat.QueueItem}.
750ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik         *
751ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik         * @param description The {@link MediaDescriptionCompat} for this item.
752ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik         * @param id An identifier for this item. It must be unique within the
753ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik         *            play queue and cannot be {@link #UNKNOWN_ID}.
754ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik         */
755ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik        public QueueItem(MediaDescriptionCompat description, long id) {
756ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik            this(null, description, id);
757ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik        }
758ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik
759ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik        private QueueItem(Object queueItem, MediaDescriptionCompat description, long id) {
760ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik            if (description == null) {
761ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik                throw new IllegalArgumentException("Description cannot be null.");
762ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik            }
763ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik            if (id == UNKNOWN_ID) {
764ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik                throw new IllegalArgumentException("Id cannot be QueueItem.UNKNOWN_ID");
765ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik            }
766ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik            mDescription = description;
767ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik            mId = id;
768ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik            mItem = queueItem;
769ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik        }
770ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik
771ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik        private QueueItem(Parcel in) {
772ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik            mDescription = MediaDescriptionCompat.CREATOR.createFromParcel(in);
773ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik            mId = in.readLong();
774ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik        }
775ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik
776ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik        /**
777ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik         * Get the description for this item.
778ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik         */
779ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik        public MediaDescriptionCompat getDescription() {
780ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik            return mDescription;
781ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik        }
782ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik
783ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik        /**
784ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik         * Get the queue id for this item.
785ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik         */
786ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik        public long getQueueId() {
787ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik            return mId;
788ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik        }
789ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik
790ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik        @Override
791ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik        public void writeToParcel(Parcel dest, int flags) {
792ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik            mDescription.writeToParcel(dest, flags);
793ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik            dest.writeLong(mId);
794ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik        }
795ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik
796ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik        @Override
797ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik        public int describeContents() {
798ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik            return 0;
799ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik        }
800ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik
801ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik        /**
802ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik         * Get the underlying
803ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik         * {@link android.media.session.MediaSession.QueueItem}.
804ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik         * <p>
805ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik         * On builds before {@link android.os.Build.VERSION_CODES#LOLLIPOP} null
806ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik         * is returned.
807ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik         *
808ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik         * @return The underlying
809ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik         *         {@link android.media.session.MediaSession.QueueItem} or null.
810ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik         */
811ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik        public Object getQueueItem() {
812ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik            if (mItem != null || android.os.Build.VERSION.SDK_INT < 21) {
813ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik                return mItem;
814ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik            }
815ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik            mItem = MediaSessionCompatApi21.QueueItem.createItem(mDescription.getMediaDescription(),
816ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik                    mId);
817ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik            return mItem;
818ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik        }
819ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik
820ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik        /**
821ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik         * Obtain a compat wrapper for an existing QueueItem.
822ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik         *
823b6362d072f329a3207aa709ac6b79a4aa3c4d522Ying Wang         * @param queueItem The {@link android.media.session.MediaSession.QueueItem} to
824ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik         *            wrap.
825ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik         * @return A compat wrapper for the provided item.
826ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik         */
827ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik        public static QueueItem obtain(Object queueItem) {
828ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik            Object descriptionObj = MediaSessionCompatApi21.QueueItem.getDescription(queueItem);
829ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik            MediaDescriptionCompat description = MediaDescriptionCompat.fromMediaDescription(
830ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik                    descriptionObj);
831ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik            long id = MediaSessionCompatApi21.QueueItem.getQueueId(queueItem);
832ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik            return new QueueItem(queueItem, description, id);
833ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik        }
834ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik
835ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik        public static final Creator<MediaSessionCompat.QueueItem>
836ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik                CREATOR = new Creator<MediaSessionCompat.QueueItem>() {
837ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik
838ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik                        @Override
839ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik                    public MediaSessionCompat.QueueItem createFromParcel(Parcel p) {
840ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik                        return new MediaSessionCompat.QueueItem(p);
841ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik                    }
842ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik
843ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik                        @Override
844ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik                    public MediaSessionCompat.QueueItem[] newArray(int size) {
845ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik                        return new MediaSessionCompat.QueueItem[size];
846ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik                    }
847ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik                };
848ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik
849ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik        @Override
850ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik        public String toString() {
851ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik            return "MediaSession.QueueItem {" +
852ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik                    "Description=" + mDescription +
853ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik                    ", Id=" + mId + " }";
854ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik        }
855ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik    }
856ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik
857e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik    /**
858e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik     * This is a wrapper for {@link ResultReceiver} for sending over aidl
859e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik     * interfaces. The framework version was not exposed to aidls until
860e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik     * {@link android.os.Build.VERSION_CODES#LOLLIPOP}.
861e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik     */
862e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik    static final class ResultReceiverWrapper implements Parcelable {
863e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        private ResultReceiver mResultReceiver;
864e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
865e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        public ResultReceiverWrapper(ResultReceiver resultReceiver) {
866e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            mResultReceiver = resultReceiver;
867e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        }
868e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
869e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        ResultReceiverWrapper(Parcel in) {
870e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            mResultReceiver = ResultReceiver.CREATOR.createFromParcel(in);
871e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        }
872e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
873e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        public static final Creator<ResultReceiverWrapper>
874e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                CREATOR = new Creator<ResultReceiverWrapper>() {
875e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            @Override
876e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            public ResultReceiverWrapper createFromParcel(Parcel p) {
877e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                return new ResultReceiverWrapper(p);
878e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
879e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
880e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            @Override
881e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            public ResultReceiverWrapper[] newArray(int size) {
882e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                return new ResultReceiverWrapper[size];
883e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
884e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        };
885e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
886e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        @Override
887e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        public int describeContents() {
888e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            return 0;
889e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        }
890e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
891e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        @Override
892e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        public void writeToParcel(Parcel dest, int flags) {
893e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            mResultReceiver.writeToParcel(dest, flags);
894e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        }
895e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik    }
896e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
8975c9469e010106467791b47b0fa83efda84491a21RoboErik    public interface OnActiveChangeListener {
8985c9469e010106467791b47b0fa83efda84491a21RoboErik        void onActiveChanged();
8995c9469e010106467791b47b0fa83efda84491a21RoboErik    }
9005c9469e010106467791b47b0fa83efda84491a21RoboErik
90124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    interface MediaSessionImpl {
9028af0092e2d7409e79779af396d63ca4146f1fb21RoboErik        void setCallback(Callback callback, Handler handler);
90324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        void setFlags(int flags);
90424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        void setPlaybackToLocal(int stream);
90524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        void setPlaybackToRemote(VolumeProviderCompat volumeProvider);
90624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        void setActive(boolean active);
90724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        boolean isActive();
90824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        void sendSessionEvent(String event, Bundle extras);
90924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        void release();
91024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        Token getSessionToken();
91124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        void setPlaybackState(PlaybackStateCompat state);
91224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        void setMetadata(MediaMetadataCompat metadata);
91385d539daa11f9f7bd61ecb8ebb4d43536c02a736RoboErik
91485d539daa11f9f7bd61ecb8ebb4d43536c02a736RoboErik        void setSessionActivity(PendingIntent pi);
915ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik
916ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik        void setMediaButtonReceiver(PendingIntent mbr);
917ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik        void setQueue(List<QueueItem> queue);
918ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik        void setQueueTitle(CharSequence title);
919ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik
920ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik        void setRatingType(int type);
921ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik        void setExtras(Bundle extras);
922ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik
92324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        Object getMediaSession();
9245c9469e010106467791b47b0fa83efda84491a21RoboErik
9255c9469e010106467791b47b0fa83efda84491a21RoboErik        Object getRemoteControlClient();
92624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    }
92724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
92824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    // TODO: compatibility implementation
92924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    static class MediaSessionImplBase implements MediaSessionImpl {
9305c9469e010106467791b47b0fa83efda84491a21RoboErik        private final Context mContext;
9315c9469e010106467791b47b0fa83efda84491a21RoboErik        private final ComponentName mComponentName;
9325c9469e010106467791b47b0fa83efda84491a21RoboErik        private final PendingIntent mMediaButtonEventReceiver;
9335c9469e010106467791b47b0fa83efda84491a21RoboErik        private final Object mRccObj;
934e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        private final MediaSessionStub mStub;
935e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        private final Token mToken;
936e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        private final MessageHandler mHandler;
937e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        private final String mPackageName;
938e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        private final String mTag;
939e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        private final AudioManager mAudioManager;
9405c9469e010106467791b47b0fa83efda84491a21RoboErik
941e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        private final Object mLock = new Object();
942e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        private final RemoteCallbackList<IMediaControllerCallback> mControllerCallbacks
943e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                = new RemoteCallbackList<IMediaControllerCallback>();
944e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
945e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        private boolean mDestroyed = false;
9465c9469e010106467791b47b0fa83efda84491a21RoboErik        private boolean mIsActive = false;
9475c9469e010106467791b47b0fa83efda84491a21RoboErik        private boolean mIsRccRegistered = false;
9485c9469e010106467791b47b0fa83efda84491a21RoboErik        private boolean mIsMbrRegistered = false;
9495c9469e010106467791b47b0fa83efda84491a21RoboErik        private Callback mCallback;
9505c9469e010106467791b47b0fa83efda84491a21RoboErik
9515c9469e010106467791b47b0fa83efda84491a21RoboErik        private int mFlags;
9525c9469e010106467791b47b0fa83efda84491a21RoboErik
9535c9469e010106467791b47b0fa83efda84491a21RoboErik        private MediaMetadataCompat mMetadata;
9545c9469e010106467791b47b0fa83efda84491a21RoboErik        private PlaybackStateCompat mState;
955e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        private PendingIntent mSessionActivity;
956e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        private List<QueueItem> mQueue;
957e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        private CharSequence mQueueTitle;
958e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        private int mRatingType;
959e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        private Bundle mExtras;
960e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
961e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        private int mVolumeType;
962e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        private int mLocalStream;
963e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        private VolumeProviderCompat mVolumeProvider;
9645c9469e010106467791b47b0fa83efda84491a21RoboErik
9651c91ca160d4a8f4f3cf3cf2a8672e0ccd16d88d4RoboErik        private VolumeProviderCompat.Callback mVolumeCallback
9661c91ca160d4a8f4f3cf3cf2a8672e0ccd16d88d4RoboErik                = new VolumeProviderCompat.Callback() {
9671c91ca160d4a8f4f3cf3cf2a8672e0ccd16d88d4RoboErik            @Override
9681c91ca160d4a8f4f3cf3cf2a8672e0ccd16d88d4RoboErik            public void onVolumeChanged(VolumeProviderCompat volumeProvider) {
9691c91ca160d4a8f4f3cf3cf2a8672e0ccd16d88d4RoboErik                if (mVolumeProvider != volumeProvider) {
9701c91ca160d4a8f4f3cf3cf2a8672e0ccd16d88d4RoboErik                    return;
9711c91ca160d4a8f4f3cf3cf2a8672e0ccd16d88d4RoboErik                }
9721c91ca160d4a8f4f3cf3cf2a8672e0ccd16d88d4RoboErik                ParcelableVolumeInfo info = new ParcelableVolumeInfo(mVolumeType, mLocalStream,
9731c91ca160d4a8f4f3cf3cf2a8672e0ccd16d88d4RoboErik                        volumeProvider.getVolumeControl(), volumeProvider.getMaxVolume(),
9741c91ca160d4a8f4f3cf3cf2a8672e0ccd16d88d4RoboErik                        volumeProvider.getCurrentVolume());
9751c91ca160d4a8f4f3cf3cf2a8672e0ccd16d88d4RoboErik                sendVolumeInfoChanged(info);
9761c91ca160d4a8f4f3cf3cf2a8672e0ccd16d88d4RoboErik            }
9771c91ca160d4a8f4f3cf3cf2a8672e0ccd16d88d4RoboErik        };
9781c91ca160d4a8f4f3cf3cf2a8672e0ccd16d88d4RoboErik
979e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        public MediaSessionImplBase(Context context, String tag, ComponentName mbrComponent,
9805c9469e010106467791b47b0fa83efda84491a21RoboErik                PendingIntent mbr) {
9815c9469e010106467791b47b0fa83efda84491a21RoboErik            if (mbrComponent == null) {
9825c9469e010106467791b47b0fa83efda84491a21RoboErik                throw new IllegalArgumentException(
9835c9469e010106467791b47b0fa83efda84491a21RoboErik                        "MediaButtonReceiver component may not be null.");
9845c9469e010106467791b47b0fa83efda84491a21RoboErik            }
9855c9469e010106467791b47b0fa83efda84491a21RoboErik            if (mbr == null) {
9865c9469e010106467791b47b0fa83efda84491a21RoboErik                // construct a PendingIntent for the media button
9875c9469e010106467791b47b0fa83efda84491a21RoboErik                Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
9885c9469e010106467791b47b0fa83efda84491a21RoboErik                // the associated intent will be handled by the component being
9895c9469e010106467791b47b0fa83efda84491a21RoboErik                // registered
9905c9469e010106467791b47b0fa83efda84491a21RoboErik                mediaButtonIntent.setComponent(mbrComponent);
9915c9469e010106467791b47b0fa83efda84491a21RoboErik                mbr = PendingIntent.getBroadcast(context,
9925c9469e010106467791b47b0fa83efda84491a21RoboErik                        0/* requestCode, ignored */, mediaButtonIntent, 0/* flags */);
9935c9469e010106467791b47b0fa83efda84491a21RoboErik            }
9945c9469e010106467791b47b0fa83efda84491a21RoboErik            mContext = context;
995e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            mPackageName = context.getPackageName();
996e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
997e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            mTag = tag;
9985c9469e010106467791b47b0fa83efda84491a21RoboErik            mComponentName = mbrComponent;
9995c9469e010106467791b47b0fa83efda84491a21RoboErik            mMediaButtonEventReceiver = mbr;
1000e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            mStub = new MediaSessionStub();
1001e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            mToken = new Token(mStub);
1002e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            mHandler = new MessageHandler(Looper.myLooper());
1003e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
1004e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            mRatingType = RatingCompat.RATING_NONE;
1005e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            mVolumeType = MediaControllerCompat.PlaybackInfo.PLAYBACK_TYPE_LOCAL;
1006e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            mLocalStream = AudioManager.STREAM_MUSIC;
10075c9469e010106467791b47b0fa83efda84491a21RoboErik            if (android.os.Build.VERSION.SDK_INT >= 14) {
10085c9469e010106467791b47b0fa83efda84491a21RoboErik                mRccObj = MediaSessionCompatApi14.createRemoteControlClient(mbr);
10095c9469e010106467791b47b0fa83efda84491a21RoboErik            } else {
10105c9469e010106467791b47b0fa83efda84491a21RoboErik                mRccObj = null;
10115c9469e010106467791b47b0fa83efda84491a21RoboErik            }
10125c9469e010106467791b47b0fa83efda84491a21RoboErik        }
10135c9469e010106467791b47b0fa83efda84491a21RoboErik
101424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        @Override
10155c9469e010106467791b47b0fa83efda84491a21RoboErik        public void setCallback(final Callback callback, Handler handler) {
10165c9469e010106467791b47b0fa83efda84491a21RoboErik            if (callback == mCallback) {
10175c9469e010106467791b47b0fa83efda84491a21RoboErik                return;
10185c9469e010106467791b47b0fa83efda84491a21RoboErik            }
10195c9469e010106467791b47b0fa83efda84491a21RoboErik            if (callback == null || android.os.Build.VERSION.SDK_INT < 18) {
10205c9469e010106467791b47b0fa83efda84491a21RoboErik                // There's nothing to register on API < 18 since media buttons
10215c9469e010106467791b47b0fa83efda84491a21RoboErik                // all go through the media button receiver
10225c9469e010106467791b47b0fa83efda84491a21RoboErik                if (android.os.Build.VERSION.SDK_INT >= 18) {
10235c9469e010106467791b47b0fa83efda84491a21RoboErik                    MediaSessionCompatApi18.setOnPlaybackPositionUpdateListener(mRccObj, null);
10245c9469e010106467791b47b0fa83efda84491a21RoboErik                }
10255c9469e010106467791b47b0fa83efda84491a21RoboErik                if (android.os.Build.VERSION.SDK_INT >= 19) {
10265c9469e010106467791b47b0fa83efda84491a21RoboErik                    MediaSessionCompatApi19.setOnMetadataUpdateListener(mRccObj, null);
10275c9469e010106467791b47b0fa83efda84491a21RoboErik                }
10285c9469e010106467791b47b0fa83efda84491a21RoboErik            } else {
10295c9469e010106467791b47b0fa83efda84491a21RoboErik                if (handler == null) {
10305c9469e010106467791b47b0fa83efda84491a21RoboErik                    handler = new Handler();
10315c9469e010106467791b47b0fa83efda84491a21RoboErik                }
10325c9469e010106467791b47b0fa83efda84491a21RoboErik                MediaSessionCompatApi14.Callback cb14 = new MediaSessionCompatApi14.Callback() {
10335c9469e010106467791b47b0fa83efda84491a21RoboErik                    @Override
10345c9469e010106467791b47b0fa83efda84491a21RoboErik                    public void onStop() {
10355c9469e010106467791b47b0fa83efda84491a21RoboErik                        callback.onStop();
10365c9469e010106467791b47b0fa83efda84491a21RoboErik                    }
10375c9469e010106467791b47b0fa83efda84491a21RoboErik
10385c9469e010106467791b47b0fa83efda84491a21RoboErik                    @Override
10395c9469e010106467791b47b0fa83efda84491a21RoboErik                    public void onSkipToPrevious() {
10405c9469e010106467791b47b0fa83efda84491a21RoboErik                        callback.onSkipToPrevious();
10415c9469e010106467791b47b0fa83efda84491a21RoboErik                    }
10425c9469e010106467791b47b0fa83efda84491a21RoboErik
10435c9469e010106467791b47b0fa83efda84491a21RoboErik                    @Override
10445c9469e010106467791b47b0fa83efda84491a21RoboErik                    public void onSkipToNext() {
10455c9469e010106467791b47b0fa83efda84491a21RoboErik                        callback.onSkipToNext();
10465c9469e010106467791b47b0fa83efda84491a21RoboErik                    }
10475c9469e010106467791b47b0fa83efda84491a21RoboErik
10485c9469e010106467791b47b0fa83efda84491a21RoboErik                    @Override
10495c9469e010106467791b47b0fa83efda84491a21RoboErik                    public void onSetRating(Object ratingObj) {
10505c9469e010106467791b47b0fa83efda84491a21RoboErik                        callback.onSetRating(RatingCompat.fromRating(ratingObj));
10515c9469e010106467791b47b0fa83efda84491a21RoboErik                    }
10525c9469e010106467791b47b0fa83efda84491a21RoboErik
10535c9469e010106467791b47b0fa83efda84491a21RoboErik                    @Override
10545c9469e010106467791b47b0fa83efda84491a21RoboErik                    public void onSeekTo(long pos) {
10555c9469e010106467791b47b0fa83efda84491a21RoboErik                        callback.onSeekTo(pos);
10565c9469e010106467791b47b0fa83efda84491a21RoboErik                    }
10575c9469e010106467791b47b0fa83efda84491a21RoboErik
10585c9469e010106467791b47b0fa83efda84491a21RoboErik                    @Override
10595c9469e010106467791b47b0fa83efda84491a21RoboErik                    public void onRewind() {
10605c9469e010106467791b47b0fa83efda84491a21RoboErik                        callback.onRewind();
10615c9469e010106467791b47b0fa83efda84491a21RoboErik                    }
10625c9469e010106467791b47b0fa83efda84491a21RoboErik
10635c9469e010106467791b47b0fa83efda84491a21RoboErik                    @Override
10645c9469e010106467791b47b0fa83efda84491a21RoboErik                    public void onPlay() {
10655c9469e010106467791b47b0fa83efda84491a21RoboErik                        callback.onPlay();
10665c9469e010106467791b47b0fa83efda84491a21RoboErik                    }
10675c9469e010106467791b47b0fa83efda84491a21RoboErik
10685c9469e010106467791b47b0fa83efda84491a21RoboErik                    @Override
10695c9469e010106467791b47b0fa83efda84491a21RoboErik                    public void onPause() {
10705c9469e010106467791b47b0fa83efda84491a21RoboErik                        callback.onPause();
10715c9469e010106467791b47b0fa83efda84491a21RoboErik                    }
10725c9469e010106467791b47b0fa83efda84491a21RoboErik
10735c9469e010106467791b47b0fa83efda84491a21RoboErik                    @Override
10745c9469e010106467791b47b0fa83efda84491a21RoboErik                    public boolean onMediaButtonEvent(Intent mediaButtonIntent) {
10755c9469e010106467791b47b0fa83efda84491a21RoboErik                        return callback.onMediaButtonEvent(mediaButtonIntent);
10765c9469e010106467791b47b0fa83efda84491a21RoboErik                    }
10775c9469e010106467791b47b0fa83efda84491a21RoboErik
10785c9469e010106467791b47b0fa83efda84491a21RoboErik                    @Override
10795c9469e010106467791b47b0fa83efda84491a21RoboErik                    public void onFastForward() {
10805c9469e010106467791b47b0fa83efda84491a21RoboErik                        callback.onFastForward();
10815c9469e010106467791b47b0fa83efda84491a21RoboErik                    }
10825c9469e010106467791b47b0fa83efda84491a21RoboErik
10835c9469e010106467791b47b0fa83efda84491a21RoboErik                    @Override
10845c9469e010106467791b47b0fa83efda84491a21RoboErik                    public void onCommand(String command, Bundle extras, ResultReceiver cb) {
10855c9469e010106467791b47b0fa83efda84491a21RoboErik                        callback.onCommand(command, extras, cb);
10865c9469e010106467791b47b0fa83efda84491a21RoboErik                    }
10875c9469e010106467791b47b0fa83efda84491a21RoboErik                };
10885c9469e010106467791b47b0fa83efda84491a21RoboErik                if (android.os.Build.VERSION.SDK_INT >= 18) {
10895c9469e010106467791b47b0fa83efda84491a21RoboErik                    Object onPositionUpdateObj = MediaSessionCompatApi18
10905c9469e010106467791b47b0fa83efda84491a21RoboErik                            .createPlaybackPositionUpdateListener(cb14);
10915c9469e010106467791b47b0fa83efda84491a21RoboErik                    MediaSessionCompatApi18.setOnPlaybackPositionUpdateListener(mRccObj,
10925c9469e010106467791b47b0fa83efda84491a21RoboErik                            onPositionUpdateObj);
10935c9469e010106467791b47b0fa83efda84491a21RoboErik                }
10945c9469e010106467791b47b0fa83efda84491a21RoboErik                if (android.os.Build.VERSION.SDK_INT >= 19) {
10955c9469e010106467791b47b0fa83efda84491a21RoboErik                    Object onMetadataUpdateObj = MediaSessionCompatApi19
10965c9469e010106467791b47b0fa83efda84491a21RoboErik                            .createMetadataUpdateListener(cb14);
10975c9469e010106467791b47b0fa83efda84491a21RoboErik                    MediaSessionCompatApi19.setOnMetadataUpdateListener(mRccObj,
10985c9469e010106467791b47b0fa83efda84491a21RoboErik                            onMetadataUpdateObj);
10995c9469e010106467791b47b0fa83efda84491a21RoboErik                }
11005c9469e010106467791b47b0fa83efda84491a21RoboErik            }
11015c9469e010106467791b47b0fa83efda84491a21RoboErik            mCallback = callback;
110224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
110324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
110424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        @Override
110524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public void setFlags(int flags) {
1106e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            synchronized (mLock) {
1107e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                mFlags = flags;
1108e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
11095c9469e010106467791b47b0fa83efda84491a21RoboErik            update();
111024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
111124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
111224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        @Override
111324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public void setPlaybackToLocal(int stream) {
11141c91ca160d4a8f4f3cf3cf2a8672e0ccd16d88d4RoboErik            if (mVolumeProvider != null) {
11151c91ca160d4a8f4f3cf3cf2a8672e0ccd16d88d4RoboErik                mVolumeProvider.setCallback(null);
11161c91ca160d4a8f4f3cf3cf2a8672e0ccd16d88d4RoboErik            }
1117e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            mVolumeType = MediaControllerCompat.PlaybackInfo.PLAYBACK_TYPE_LOCAL;
1118e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            ParcelableVolumeInfo info = new ParcelableVolumeInfo(mVolumeType, mLocalStream,
1119e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                    VolumeProviderCompat.VOLUME_CONTROL_ABSOLUTE,
1120e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                    mAudioManager.getStreamMaxVolume(mLocalStream),
1121e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                    mAudioManager.getStreamVolume(mLocalStream));
1122e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            sendVolumeInfoChanged(info);
112324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
112424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
112524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        @Override
112624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public void setPlaybackToRemote(VolumeProviderCompat volumeProvider) {
1127e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            if (volumeProvider == null) {
1128e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                throw new IllegalArgumentException("volumeProvider may not be null");
1129e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
11301c91ca160d4a8f4f3cf3cf2a8672e0ccd16d88d4RoboErik            if (mVolumeProvider != null) {
11311c91ca160d4a8f4f3cf3cf2a8672e0ccd16d88d4RoboErik                mVolumeProvider.setCallback(null);
11321c91ca160d4a8f4f3cf3cf2a8672e0ccd16d88d4RoboErik            }
1133e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            mVolumeType = MediaControllerCompat.PlaybackInfo.PLAYBACK_TYPE_REMOTE;
1134e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            mVolumeProvider = volumeProvider;
1135e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            ParcelableVolumeInfo info = new ParcelableVolumeInfo(mVolumeType, mLocalStream,
1136e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                    mVolumeProvider.getVolumeControl(), mVolumeProvider.getMaxVolume(),
1137e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                    mVolumeProvider.getCurrentVolume());
1138e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            sendVolumeInfoChanged(info);
11391c91ca160d4a8f4f3cf3cf2a8672e0ccd16d88d4RoboErik
11401c91ca160d4a8f4f3cf3cf2a8672e0ccd16d88d4RoboErik            volumeProvider.setCallback(mVolumeCallback);
114124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
114224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
114324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        @Override
114424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public void setActive(boolean active) {
11455c9469e010106467791b47b0fa83efda84491a21RoboErik            if (active == mIsActive) {
11465c9469e010106467791b47b0fa83efda84491a21RoboErik                return;
11475c9469e010106467791b47b0fa83efda84491a21RoboErik            }
11485c9469e010106467791b47b0fa83efda84491a21RoboErik            mIsActive = active;
11495c9469e010106467791b47b0fa83efda84491a21RoboErik            if (update()) {
11505c9469e010106467791b47b0fa83efda84491a21RoboErik                setMetadata(mMetadata);
11515c9469e010106467791b47b0fa83efda84491a21RoboErik                setPlaybackState(mState);
11525c9469e010106467791b47b0fa83efda84491a21RoboErik            }
115324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
115424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
115524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        @Override
115624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public boolean isActive() {
11575c9469e010106467791b47b0fa83efda84491a21RoboErik            return mIsActive;
115824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
115924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
116024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        @Override
116124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public void sendSessionEvent(String event, Bundle extras) {
1162e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            sendEvent(event, extras);
116324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
116424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
116524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        @Override
116624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public void release() {
11675c9469e010106467791b47b0fa83efda84491a21RoboErik            mIsActive = false;
1168e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            mDestroyed = true;
11695c9469e010106467791b47b0fa83efda84491a21RoboErik            update();
1170e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            sendSessionDestroyed();
117124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
117224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
117324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        @Override
117424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public Token getSessionToken() {
1175e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            return mToken;
117624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
117724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
117824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        @Override
117924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public void setPlaybackState(PlaybackStateCompat state) {
1180e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            synchronized (mLock) {
1181e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                mState = state;
1182e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
1183e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            sendState(state);
11845c9469e010106467791b47b0fa83efda84491a21RoboErik            if (!mIsActive) {
11855c9469e010106467791b47b0fa83efda84491a21RoboErik                // Don't set the state until after the RCC is registered
11865c9469e010106467791b47b0fa83efda84491a21RoboErik                return;
11875c9469e010106467791b47b0fa83efda84491a21RoboErik            }
11885c9469e010106467791b47b0fa83efda84491a21RoboErik            if (state == null) {
11895c9469e010106467791b47b0fa83efda84491a21RoboErik                if (android.os.Build.VERSION.SDK_INT >= 14) {
11905c9469e010106467791b47b0fa83efda84491a21RoboErik                    MediaSessionCompatApi14.setState(mRccObj, PlaybackStateCompat.STATE_NONE);
11915c9469e010106467791b47b0fa83efda84491a21RoboErik                }
11925c9469e010106467791b47b0fa83efda84491a21RoboErik            } else {
11935c9469e010106467791b47b0fa83efda84491a21RoboErik                if (android.os.Build.VERSION.SDK_INT >= 18) {
11945c9469e010106467791b47b0fa83efda84491a21RoboErik                    MediaSessionCompatApi18.setState(mRccObj, state.getState(), state.getPosition(),
11955c9469e010106467791b47b0fa83efda84491a21RoboErik                            state.getPlaybackSpeed(), state.getLastPositionUpdateTime());
11965c9469e010106467791b47b0fa83efda84491a21RoboErik                } else if (android.os.Build.VERSION.SDK_INT >= 14) {
11975c9469e010106467791b47b0fa83efda84491a21RoboErik                    MediaSessionCompatApi14.setState(mRccObj, state.getState());
11985c9469e010106467791b47b0fa83efda84491a21RoboErik                }
11995c9469e010106467791b47b0fa83efda84491a21RoboErik            }
120024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
120124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
120224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        @Override
120324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public void setMetadata(MediaMetadataCompat metadata) {
1204e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            synchronized (mLock) {
1205e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                mMetadata = metadata;
1206e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
1207e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            sendMetadata(metadata);
12085c9469e010106467791b47b0fa83efda84491a21RoboErik            if (!mIsActive) {
12095c9469e010106467791b47b0fa83efda84491a21RoboErik                // Don't set metadata until after the rcc has been registered
12105c9469e010106467791b47b0fa83efda84491a21RoboErik                return;
12115c9469e010106467791b47b0fa83efda84491a21RoboErik            }
12125c9469e010106467791b47b0fa83efda84491a21RoboErik            if (android.os.Build.VERSION.SDK_INT >= 19) {
12135c9469e010106467791b47b0fa83efda84491a21RoboErik                boolean canRate = mState != null
12145c9469e010106467791b47b0fa83efda84491a21RoboErik                        && (mState.getActions() & PlaybackStateCompat.ACTION_SET_RATING) != 0;
12155c9469e010106467791b47b0fa83efda84491a21RoboErik                MediaSessionCompatApi19.setMetadata(mRccObj,
12165c9469e010106467791b47b0fa83efda84491a21RoboErik                        metadata == null ? null : metadata.getBundle(), canRate);
12175c9469e010106467791b47b0fa83efda84491a21RoboErik            } else if (android.os.Build.VERSION.SDK_INT >= 14) {
12185c9469e010106467791b47b0fa83efda84491a21RoboErik                MediaSessionCompatApi14.setMetadata(mRccObj,
12195c9469e010106467791b47b0fa83efda84491a21RoboErik                        metadata == null ? null : metadata.getBundle());
12205c9469e010106467791b47b0fa83efda84491a21RoboErik            }
122124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
122224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
122324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        @Override
122485d539daa11f9f7bd61ecb8ebb4d43536c02a736RoboErik        public void setSessionActivity(PendingIntent pi) {
1225e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            synchronized (mLock) {
1226e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                mSessionActivity = pi;
1227e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
122885d539daa11f9f7bd61ecb8ebb4d43536c02a736RoboErik        }
122985d539daa11f9f7bd61ecb8ebb4d43536c02a736RoboErik
123085d539daa11f9f7bd61ecb8ebb4d43536c02a736RoboErik        @Override
1231ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik        public void setMediaButtonReceiver(PendingIntent mbr) {
12325c9469e010106467791b47b0fa83efda84491a21RoboErik            // Do nothing, changing this is not supported before API 21.
1233ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik        }
1234ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik
1235ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik        @Override
1236ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik        public void setQueue(List<QueueItem> queue) {
1237e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            mQueue = queue;
1238e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            sendQueue(queue);
1239ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik        }
1240ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik
1241ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik        @Override
1242ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik        public void setQueueTitle(CharSequence title) {
1243e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            mQueueTitle = title;
1244e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            sendQueueTitle(title);
1245ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik        }
1246ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik
1247ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik        @Override
124824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public Object getMediaSession() {
124924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            return null;
125024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
1251ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik
1252ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik        @Override
12535c9469e010106467791b47b0fa83efda84491a21RoboErik        public Object getRemoteControlClient() {
12545c9469e010106467791b47b0fa83efda84491a21RoboErik            return mRccObj;
12555c9469e010106467791b47b0fa83efda84491a21RoboErik        }
12565c9469e010106467791b47b0fa83efda84491a21RoboErik
12575c9469e010106467791b47b0fa83efda84491a21RoboErik        @Override
1258ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik        public void setRatingType(int type) {
1259e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            mRatingType = type;
1260ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik        }
1261ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik
1262ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik        @Override
1263ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik        public void setExtras(Bundle extras) {
1264e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            mExtras = extras;
1265ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik        }
12665c9469e010106467791b47b0fa83efda84491a21RoboErik
12675c9469e010106467791b47b0fa83efda84491a21RoboErik        // Registers/unregisters the RCC and MediaButtonEventReceiver as needed.
12685c9469e010106467791b47b0fa83efda84491a21RoboErik        private boolean update() {
12695c9469e010106467791b47b0fa83efda84491a21RoboErik            boolean registeredRcc = false;
12705c9469e010106467791b47b0fa83efda84491a21RoboErik            if (mIsActive) {
12715c9469e010106467791b47b0fa83efda84491a21RoboErik                // On API 8+ register a MBR if it's supported, unregister it
12725c9469e010106467791b47b0fa83efda84491a21RoboErik                // if support was removed.
12735c9469e010106467791b47b0fa83efda84491a21RoboErik                if (android.os.Build.VERSION.SDK_INT >= 8) {
12745c9469e010106467791b47b0fa83efda84491a21RoboErik                    if (!mIsMbrRegistered && (mFlags & FLAG_HANDLES_MEDIA_BUTTONS) != 0) {
12755c9469e010106467791b47b0fa83efda84491a21RoboErik                        if (android.os.Build.VERSION.SDK_INT >= 18) {
12765c9469e010106467791b47b0fa83efda84491a21RoboErik                            MediaSessionCompatApi18.registerMediaButtonEventReceiver(mContext,
12775c9469e010106467791b47b0fa83efda84491a21RoboErik                                    mMediaButtonEventReceiver);
12785c9469e010106467791b47b0fa83efda84491a21RoboErik                        } else {
12795c9469e010106467791b47b0fa83efda84491a21RoboErik                            MediaSessionCompatApi8.registerMediaButtonEventReceiver(mContext,
12805c9469e010106467791b47b0fa83efda84491a21RoboErik                                    mComponentName);
12815c9469e010106467791b47b0fa83efda84491a21RoboErik                        }
12825c9469e010106467791b47b0fa83efda84491a21RoboErik                        mIsMbrRegistered = true;
12835c9469e010106467791b47b0fa83efda84491a21RoboErik                    } else if (mIsMbrRegistered && (mFlags & FLAG_HANDLES_MEDIA_BUTTONS) == 0) {
12845c9469e010106467791b47b0fa83efda84491a21RoboErik                        if (android.os.Build.VERSION.SDK_INT >= 18) {
12855c9469e010106467791b47b0fa83efda84491a21RoboErik                            MediaSessionCompatApi18.unregisterMediaButtonEventReceiver(mContext,
12865c9469e010106467791b47b0fa83efda84491a21RoboErik                                    mMediaButtonEventReceiver);
12875c9469e010106467791b47b0fa83efda84491a21RoboErik                        } else {
12885c9469e010106467791b47b0fa83efda84491a21RoboErik                            MediaSessionCompatApi8.unregisterMediaButtonEventReceiver(mContext,
12895c9469e010106467791b47b0fa83efda84491a21RoboErik                                    mComponentName);
12905c9469e010106467791b47b0fa83efda84491a21RoboErik                        }
12915c9469e010106467791b47b0fa83efda84491a21RoboErik                        mIsMbrRegistered = false;
12925c9469e010106467791b47b0fa83efda84491a21RoboErik                    }
12935c9469e010106467791b47b0fa83efda84491a21RoboErik                }
12945c9469e010106467791b47b0fa83efda84491a21RoboErik                // On API 14+ register a RCC if it's supported, unregister it if
12955c9469e010106467791b47b0fa83efda84491a21RoboErik                // not.
12965c9469e010106467791b47b0fa83efda84491a21RoboErik                if (android.os.Build.VERSION.SDK_INT >= 14) {
12975c9469e010106467791b47b0fa83efda84491a21RoboErik                    if (!mIsRccRegistered && (mFlags & FLAG_HANDLES_TRANSPORT_CONTROLS) != 0) {
12985c9469e010106467791b47b0fa83efda84491a21RoboErik                        MediaSessionCompatApi14.registerRemoteControlClient(mContext, mRccObj);
12995c9469e010106467791b47b0fa83efda84491a21RoboErik                        mIsRccRegistered = true;
13005c9469e010106467791b47b0fa83efda84491a21RoboErik                        registeredRcc = true;
13015c9469e010106467791b47b0fa83efda84491a21RoboErik                    } else if (mIsRccRegistered
13025c9469e010106467791b47b0fa83efda84491a21RoboErik                            && (mFlags & FLAG_HANDLES_TRANSPORT_CONTROLS) == 0) {
13035c9469e010106467791b47b0fa83efda84491a21RoboErik                        MediaSessionCompatApi14.unregisterRemoteControlClient(mContext, mRccObj);
13045c9469e010106467791b47b0fa83efda84491a21RoboErik                        mIsRccRegistered = false;
13055c9469e010106467791b47b0fa83efda84491a21RoboErik                    }
13065c9469e010106467791b47b0fa83efda84491a21RoboErik                }
13075c9469e010106467791b47b0fa83efda84491a21RoboErik            } else {
13085c9469e010106467791b47b0fa83efda84491a21RoboErik                // When inactive remove any registered components.
13095c9469e010106467791b47b0fa83efda84491a21RoboErik                if (mIsMbrRegistered) {
13105c9469e010106467791b47b0fa83efda84491a21RoboErik                    if (android.os.Build.VERSION.SDK_INT >= 18) {
13115c9469e010106467791b47b0fa83efda84491a21RoboErik                        MediaSessionCompatApi18.unregisterMediaButtonEventReceiver(mContext,
13125c9469e010106467791b47b0fa83efda84491a21RoboErik                                mMediaButtonEventReceiver);
13135c9469e010106467791b47b0fa83efda84491a21RoboErik                    } else {
13145c9469e010106467791b47b0fa83efda84491a21RoboErik                        MediaSessionCompatApi8.unregisterMediaButtonEventReceiver(mContext,
13155c9469e010106467791b47b0fa83efda84491a21RoboErik                                mComponentName);
13165c9469e010106467791b47b0fa83efda84491a21RoboErik                    }
13175c9469e010106467791b47b0fa83efda84491a21RoboErik                    mIsMbrRegistered = false;
13185c9469e010106467791b47b0fa83efda84491a21RoboErik                }
13195c9469e010106467791b47b0fa83efda84491a21RoboErik                if (mIsRccRegistered) {
13205c9469e010106467791b47b0fa83efda84491a21RoboErik                    MediaSessionCompatApi14.unregisterRemoteControlClient(mContext, mRccObj);
13215c9469e010106467791b47b0fa83efda84491a21RoboErik                    mIsRccRegistered = false;
13225c9469e010106467791b47b0fa83efda84491a21RoboErik                }
13235c9469e010106467791b47b0fa83efda84491a21RoboErik            }
13245c9469e010106467791b47b0fa83efda84491a21RoboErik            return registeredRcc;
13255c9469e010106467791b47b0fa83efda84491a21RoboErik        }
1326e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
1327e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        private void adjustVolume(int direction, int flags) {
1328e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            if (mVolumeType == MediaControllerCompat.PlaybackInfo.PLAYBACK_TYPE_REMOTE) {
1329e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                if (mVolumeProvider != null) {
1330e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                    mVolumeProvider.onAdjustVolume(direction);
1331e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                }
1332e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            } else {
1333e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                mAudioManager.adjustStreamVolume(direction, mLocalStream, flags);
1334e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
1335e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        }
1336e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
1337e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        private void setVolumeTo(int value, int flags) {
1338e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            if (mVolumeType == MediaControllerCompat.PlaybackInfo.PLAYBACK_TYPE_REMOTE) {
1339e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                if (mVolumeProvider != null) {
1340e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                    mVolumeProvider.onSetVolumeTo(value);
1341e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                }
1342e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            } else {
1343e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                mAudioManager.setStreamVolume(mLocalStream, value, flags);
1344e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
1345e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        }
1346e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
1347e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        private PlaybackStateCompat getStateWithUpdatedPosition() {
1348e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            PlaybackStateCompat state;
1349e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            long duration = -1;
1350e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            synchronized (mLock) {
1351e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                state = mState;
1352e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                if (mMetadata != null
1353e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                        && mMetadata.containsKey(MediaMetadataCompat.METADATA_KEY_DURATION)) {
1354e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                    duration = mMetadata.getLong(MediaMetadataCompat.METADATA_KEY_DURATION);
1355e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                }
1356e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
1357e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
1358e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            PlaybackStateCompat result = null;
1359e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            if (state != null) {
1360e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                if (state.getState() == PlaybackStateCompat.STATE_PLAYING
1361e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                        || state.getState() == PlaybackStateCompat.STATE_FAST_FORWARDING
1362e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                        || state.getState() == PlaybackStateCompat.STATE_REWINDING) {
1363e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                    long updateTime = state.getLastPositionUpdateTime();
1364e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                    long currentTime = SystemClock.elapsedRealtime();
1365e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                    if (updateTime > 0) {
1366e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                        long position = (long) (state.getPlaybackSpeed()
1367e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                                * (currentTime - updateTime)) + state.getPosition();
1368e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                        if (duration >= 0 && position > duration) {
1369e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                            position = duration;
1370e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                        } else if (position < 0) {
1371e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                            position = 0;
1372e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                        }
1373e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                        PlaybackStateCompat.Builder builder = new PlaybackStateCompat.Builder(
1374e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                                state);
1375e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                        builder.setState(state.getState(), position, state.getPlaybackSpeed(),
1376e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                                currentTime);
1377e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                        result = builder.build();
1378e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                    }
1379e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                }
1380e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
1381e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            return result == null ? state : result;
1382e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        }
1383e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
1384e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        private void sendVolumeInfoChanged(ParcelableVolumeInfo info) {
1385e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            int size = mControllerCallbacks.beginBroadcast();
1386e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            for (int i = size - 1; i >= 0; i--) {
1387e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                IMediaControllerCallback cb = mControllerCallbacks.getBroadcastItem(i);
1388e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                try {
1389e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                    cb.onVolumeInfoChanged(info);
1390e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                } catch (RemoteException e) {
1391e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                }
1392e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
1393e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            mControllerCallbacks.finishBroadcast();
1394e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        }
1395e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
1396e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        private void sendSessionDestroyed() {
1397e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            int size = mControllerCallbacks.beginBroadcast();
1398e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            for (int i = size - 1; i >= 0; i--) {
1399e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                IMediaControllerCallback cb = mControllerCallbacks.getBroadcastItem(i);
1400e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                try {
1401e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                    cb.onSessionDestroyed();;
1402e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                } catch (RemoteException e) {
1403e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                }
1404e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
1405e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            mControllerCallbacks.finishBroadcast();
1406e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            mControllerCallbacks.kill();
1407e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        }
1408e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
1409e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        private void sendEvent(String event, Bundle extras) {
1410e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            int size = mControllerCallbacks.beginBroadcast();
1411e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            for (int i = size - 1; i >= 0; i--) {
1412e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                IMediaControllerCallback cb = mControllerCallbacks.getBroadcastItem(i);
1413e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                try {
1414e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                    cb.onEvent(event, extras);
1415e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                } catch (RemoteException e) {
1416e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                }
1417e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
1418e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            mControllerCallbacks.finishBroadcast();
1419e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        }
1420e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
1421e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        private void sendState(PlaybackStateCompat state) {
1422e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            int size = mControllerCallbacks.beginBroadcast();
1423e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            for (int i = size - 1; i >= 0; i--) {
1424e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                IMediaControllerCallback cb = mControllerCallbacks.getBroadcastItem(i);
1425e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                try {
1426e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                    cb.onPlaybackStateChanged(state);
1427e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                } catch (RemoteException e) {
1428e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                }
1429e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
1430e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            mControllerCallbacks.finishBroadcast();
1431e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        }
1432e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
1433e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        private void sendMetadata(MediaMetadataCompat metadata) {
1434e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            int size = mControllerCallbacks.beginBroadcast();
1435e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            for (int i = size - 1; i >= 0; i--) {
1436e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                IMediaControllerCallback cb = mControllerCallbacks.getBroadcastItem(i);
1437e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                try {
1438e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                    cb.onMetadataChanged(metadata);
1439e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                } catch (RemoteException e) {
1440e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                }
1441e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
1442e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            mControllerCallbacks.finishBroadcast();
1443e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        }
1444e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
1445e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        private void sendQueue(List<QueueItem> queue) {
1446e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            int size = mControllerCallbacks.beginBroadcast();
1447e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            for (int i = size - 1; i >= 0; i--) {
1448e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                IMediaControllerCallback cb = mControllerCallbacks.getBroadcastItem(i);
1449e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                try {
1450e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                    cb.onQueueChanged(queue);
1451e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                } catch (RemoteException e) {
1452e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                }
1453e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
1454e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            mControllerCallbacks.finishBroadcast();
1455e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        }
1456e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
1457e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        private void sendQueueTitle(CharSequence queueTitle) {
1458e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            int size = mControllerCallbacks.beginBroadcast();
1459e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            for (int i = size - 1; i >= 0; i--) {
1460e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                IMediaControllerCallback cb = mControllerCallbacks.getBroadcastItem(i);
1461e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                try {
1462e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                    cb.onQueueTitleChanged(queueTitle);
1463e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                } catch (RemoteException e) {
1464e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                }
1465e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
1466e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            mControllerCallbacks.finishBroadcast();
1467e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        }
1468e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
1469e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        class MediaSessionStub extends IMediaSession.Stub {
1470e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            @Override
1471e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            public void sendCommand(String command, Bundle args, ResultReceiverWrapper cb) {
1472e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                mHandler.post(MessageHandler.MSG_COMMAND,
1473e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                        new Command(command, args, cb.mResultReceiver));
1474e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
1475e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
1476e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            @Override
1477e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            public boolean sendMediaButton(KeyEvent mediaButton) {
1478e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                boolean handlesMediaButtons =
1479e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                        (mFlags & MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS) != 0;
1480e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                if (handlesMediaButtons) {
1481e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                    mHandler.post(MessageHandler.MSG_MEDIA_BUTTON, mediaButton);
1482e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                }
1483e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                return handlesMediaButtons;
1484e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
1485e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
1486e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            @Override
1487e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            public void registerCallbackListener(IMediaControllerCallback cb) {
1488e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                // If this session is already destroyed tell the caller and
1489e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                // don't add them.
1490e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                if (mDestroyed) {
1491e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                    try {
1492e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                        cb.onSessionDestroyed();
1493e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                    } catch (Exception e) {
1494e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                        // ignored
1495e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                    }
1496e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                    return;
1497e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                }
1498e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                mControllerCallbacks.register(cb);
1499e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
1500e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
1501e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            @Override
1502e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            public void unregisterCallbackListener(IMediaControllerCallback cb) {
1503e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                mControllerCallbacks.unregister(cb);
1504e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
1505e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
1506e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            @Override
1507e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            public String getPackageName() {
1508e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                // mPackageName is final so doesn't need synchronize block
1509e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                return mPackageName;
1510e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
1511e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
1512e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            @Override
1513e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            public String getTag() {
1514e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                // mTag is final so doesn't need synchronize block
1515e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                return mTag;
1516e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
1517e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
1518e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            @Override
1519e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            public PendingIntent getLaunchPendingIntent() {
1520e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                synchronized (mLock) {
1521e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                    return mSessionActivity;
1522e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                }
1523e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
1524e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
1525e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            @Override
1526e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            public long getFlags() {
1527e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                synchronized (mLock) {
1528e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                    return mFlags;
1529e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                }
1530e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
1531e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
1532e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            @Override
1533e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            public ParcelableVolumeInfo getVolumeAttributes() {
1534e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                int controlType;
1535e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                int max;
1536e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                int current;
1537e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                int stream;
1538e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                int volumeType;
1539e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                synchronized (mLock) {
1540e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                    volumeType = mVolumeType;
1541e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                    stream = mLocalStream;
1542e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                    VolumeProviderCompat vp = mVolumeProvider;
1543e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                    if (volumeType == MediaControllerCompat.PlaybackInfo.PLAYBACK_TYPE_REMOTE) {
1544e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                        controlType = vp.getVolumeControl();
1545e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                        max = vp.getMaxVolume();
1546e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                        current = vp.getCurrentVolume();
1547e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                    } else {
1548e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                        controlType = VolumeProviderCompat.VOLUME_CONTROL_ABSOLUTE;
1549e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                        max = mAudioManager.getStreamMaxVolume(stream);
1550e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                        current = mAudioManager.getStreamVolume(stream);
1551e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                    }
1552e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                }
1553e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                return new ParcelableVolumeInfo(volumeType, stream, controlType, max, current);
1554e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
1555e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
1556e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            @Override
1557e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            public void adjustVolume(int direction, int flags, String packageName) {
1558e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                MediaSessionImplBase.this.adjustVolume(direction, flags);
1559e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
1560e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
1561e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            @Override
1562e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            public void setVolumeTo(int value, int flags, String packageName) {
1563e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                MediaSessionImplBase.this.setVolumeTo(value, flags);
1564e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
1565e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
1566e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            @Override
1567e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            public void play() throws RemoteException {
1568e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                mHandler.post(MessageHandler.MSG_PLAY);
1569e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
1570e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
1571e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            @Override
1572e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            public void playFromMediaId(String mediaId, Bundle extras) throws RemoteException {
1573e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                mHandler.post(MessageHandler.MSG_PLAY_MEDIA_ID, mediaId, extras);
1574e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
1575e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
1576e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            @Override
1577e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            public void playFromSearch(String query, Bundle extras) throws RemoteException {
1578e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                mHandler.post(MessageHandler.MSG_PLAY_SEARCH, query, extras);
1579e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
1580e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
1581e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            @Override
1582e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            public void skipToQueueItem(long id) {
1583e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                mHandler.post(MessageHandler.MSG_SKIP_TO_ITEM, id);
1584e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
1585e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
1586e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            @Override
1587e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            public void pause() throws RemoteException {
1588e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                mHandler.post(MessageHandler.MSG_PAUSE);
1589e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
1590e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
1591e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            @Override
1592e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            public void stop() throws RemoteException {
1593e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                mHandler.post(MessageHandler.MSG_STOP);
1594e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
1595e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
1596e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            @Override
1597e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            public void next() throws RemoteException {
1598e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                mHandler.post(MessageHandler.MSG_NEXT);
1599e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
1600e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
1601e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            @Override
1602e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            public void previous() throws RemoteException {
1603e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                mHandler.post(MessageHandler.MSG_PREVIOUS);
1604e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
1605e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
1606e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            @Override
1607e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            public void fastForward() throws RemoteException {
1608e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                mHandler.post(MessageHandler.MSG_FAST_FORWARD);
1609e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
1610e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
1611e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            @Override
1612e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            public void rewind() throws RemoteException {
1613e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                mHandler.post(MessageHandler.MSG_REWIND);
1614e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
1615e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
1616e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            @Override
1617e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            public void seekTo(long pos) throws RemoteException {
1618e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                mHandler.post(MessageHandler.MSG_SEEK_TO, pos);
1619e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
1620e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
1621e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            @Override
1622e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            public void rate(RatingCompat rating) throws RemoteException {
1623e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                mHandler.post(MessageHandler.MSG_RATE, rating);
1624e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
1625e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
1626e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            @Override
1627e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            public void sendCustomAction(String action, Bundle args)
1628e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                    throws RemoteException {
1629e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                mHandler.post(MessageHandler.MSG_CUSTOM_ACTION, action, args);
1630e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
1631e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
1632e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            @Override
1633e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            public MediaMetadataCompat getMetadata() {
1634e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                return mMetadata;
1635e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
1636e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
1637e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            @Override
1638e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            public PlaybackStateCompat getPlaybackState() {
1639e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                return getStateWithUpdatedPosition();
1640e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
1641e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
1642e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            @Override
1643e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            public List<QueueItem> getQueue() {
1644e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                synchronized (mLock) {
1645e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                    return mQueue;
1646e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                }
1647e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
1648e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
1649e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            @Override
1650e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            public CharSequence getQueueTitle() {
1651e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                return mQueueTitle;
1652e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
1653e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
1654e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            @Override
1655e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            public Bundle getExtras() {
1656e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                synchronized (mLock) {
1657e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                    return mExtras;
1658e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                }
1659e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
1660e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
1661e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            @Override
1662e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            public int getRatingType() {
1663e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                return mRatingType;
1664e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
1665e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
1666e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            @Override
1667e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            public boolean isTransportControlEnabled() {
1668e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                return (mFlags & FLAG_HANDLES_TRANSPORT_CONTROLS) != 0;
1669e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
1670e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        }
1671e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
1672e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        private static final class Command {
1673e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            public final String command;
1674e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            public final Bundle extras;
1675e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            public final ResultReceiver stub;
1676e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
1677e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            public Command(String command, Bundle extras, ResultReceiver stub) {
1678e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                this.command = command;
1679e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                this.extras = extras;
1680e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                this.stub = stub;
1681e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
1682e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        }
1683e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
1684e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        private class MessageHandler extends Handler {
1685e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
1686e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            private static final int MSG_PLAY = 1;
1687e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            private static final int MSG_PLAY_MEDIA_ID = 2;
1688e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            private static final int MSG_PLAY_SEARCH = 3;
1689e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            private static final int MSG_SKIP_TO_ITEM = 4;
1690e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            private static final int MSG_PAUSE = 5;
1691e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            private static final int MSG_STOP = 6;
1692e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            private static final int MSG_NEXT = 7;
1693e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            private static final int MSG_PREVIOUS = 8;
1694e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            private static final int MSG_FAST_FORWARD = 9;
1695e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            private static final int MSG_REWIND = 10;
1696e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            private static final int MSG_SEEK_TO = 11;
1697e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            private static final int MSG_RATE = 12;
1698e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            private static final int MSG_CUSTOM_ACTION = 13;
1699e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            private static final int MSG_MEDIA_BUTTON = 14;
1700e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            private static final int MSG_COMMAND = 15;
1701e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            private static final int MSG_ADJUST_VOLUME = 16;
1702e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            private static final int MSG_SET_VOLUME = 17;
1703e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
1704e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            public MessageHandler(Looper looper) {
1705e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                super(looper);
1706e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
1707e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
1708e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            public void post(int what, Object obj, Bundle bundle) {
1709e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                Message msg = obtainMessage(what, obj);
1710e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                msg.setData(bundle);
1711e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                msg.sendToTarget();
1712e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
1713e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
1714e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            public void post(int what, Object obj) {
1715e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                obtainMessage(what, obj).sendToTarget();
1716e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
1717e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
1718e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            public void post(int what) {
1719e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                post(what, null);
1720e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
1721e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
1722e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            public void post(int what, Object obj, int arg1) {
1723e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                obtainMessage(what, arg1, 0, obj).sendToTarget();
1724e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
1725e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
1726e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            @Override
1727e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            public void handleMessage(Message msg) {
1728e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                if (mCallback == null) {
1729e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                    return;
1730e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                }
1731e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                switch (msg.what) {
1732e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                    case MSG_PLAY:
1733e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                        mCallback.onPlay();
1734e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                        break;
1735e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                    case MSG_PLAY_MEDIA_ID:
1736e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                        mCallback.onPlayFromMediaId((String) msg.obj, msg.getData());
1737e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                        break;
1738e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                    case MSG_PLAY_SEARCH:
1739e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                        mCallback.onPlayFromSearch((String) msg.obj, msg.getData());
1740e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                        break;
1741e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                    case MSG_SKIP_TO_ITEM:
1742e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                        mCallback.onSkipToQueueItem((Long) msg.obj);
1743e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                        break;
1744e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                    case MSG_PAUSE:
1745e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                        mCallback.onPause();
1746e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                        break;
1747e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                    case MSG_STOP:
1748e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                        mCallback.onStop();
1749e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                        break;
1750e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                    case MSG_NEXT:
1751e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                        mCallback.onSkipToNext();
1752e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                        break;
1753e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                    case MSG_PREVIOUS:
1754e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                        mCallback.onSkipToPrevious();
1755e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                        break;
1756e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                    case MSG_FAST_FORWARD:
1757e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                        mCallback.onFastForward();
1758e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                        break;
1759e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                    case MSG_REWIND:
1760e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                        mCallback.onRewind();
1761e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                        break;
1762e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                    case MSG_SEEK_TO:
1763e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                        mCallback.onSeekTo((Long) msg.obj);
1764e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                        break;
1765e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                    case MSG_RATE:
1766e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                        mCallback.onSetRating((RatingCompat) msg.obj);
1767e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                        break;
1768e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                    case MSG_CUSTOM_ACTION:
1769e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                        mCallback.onCustomAction((String) msg.obj, msg.getData());
1770e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                        break;
1771e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                    case MSG_MEDIA_BUTTON:
1772e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                        mCallback.onMediaButtonEvent((Intent) msg.obj);
1773e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                        break;
1774e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                    case MSG_COMMAND:
1775e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                        Command cmd = (Command) msg.obj;
1776e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                        mCallback.onCommand(cmd.command, cmd.extras, cmd.stub);
1777e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                        break;
1778e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                    case MSG_ADJUST_VOLUME:
1779e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                        adjustVolume((int) msg.obj, 0);
1780e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                        break;
1781e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                    case MSG_SET_VOLUME:
1782e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                        setVolumeTo((int) msg.obj, 0);
1783e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                        break;
1784e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                }
1785e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
1786e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        }
178724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    }
178824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
178924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    static class MediaSessionImplApi21 implements MediaSessionImpl {
179024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        private final Object mSessionObj;
179124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        private final Token mToken;
179224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
1793ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik        private PendingIntent mMediaButtonIntent;
1794ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik
179524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public MediaSessionImplApi21(Context context, String tag) {
179624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            mSessionObj = MediaSessionCompatApi21.createSession(context, tag);
179724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            mToken = new Token(MediaSessionCompatApi21.getSessionToken(mSessionObj));
179824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
179924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
1800bbcdf78e350d58ecd6baa75e282d4908d3129fe2RoboErik        public MediaSessionImplApi21(Object mediaSession) {
1801bbcdf78e350d58ecd6baa75e282d4908d3129fe2RoboErik            mSessionObj = MediaSessionCompatApi21.verifySession(mediaSession);
1802bbcdf78e350d58ecd6baa75e282d4908d3129fe2RoboErik            mToken = new Token(MediaSessionCompatApi21.getSessionToken(mSessionObj));
1803bbcdf78e350d58ecd6baa75e282d4908d3129fe2RoboErik        }
1804bbcdf78e350d58ecd6baa75e282d4908d3129fe2RoboErik
180524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        @Override
18068af0092e2d7409e79779af396d63ca4146f1fb21RoboErik        public void setCallback(Callback callback, Handler handler) {
18078af0092e2d7409e79779af396d63ca4146f1fb21RoboErik            MediaSessionCompatApi21.setCallback(mSessionObj, callback.mCallbackObj, handler);
180824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
180924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
181024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        @Override
181124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public void setFlags(int flags) {
181224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            MediaSessionCompatApi21.setFlags(mSessionObj, flags);
181324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
181424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
181524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        @Override
181624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public void setPlaybackToLocal(int stream) {
181724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            MediaSessionCompatApi21.setPlaybackToLocal(mSessionObj, stream);
181824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
181924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
182024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        @Override
182124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public void setPlaybackToRemote(VolumeProviderCompat volumeProvider) {
182224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            MediaSessionCompatApi21.setPlaybackToRemote(mSessionObj,
182324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown                    volumeProvider.getVolumeProvider());
182424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
182524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
182624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        @Override
182724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public void setActive(boolean active) {
182824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            MediaSessionCompatApi21.setActive(mSessionObj, active);
182924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
183024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
183124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        @Override
183224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public boolean isActive() {
183324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            return MediaSessionCompatApi21.isActive(mSessionObj);
183424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
183524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
183624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        @Override
183724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public void sendSessionEvent(String event, Bundle extras) {
183824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            MediaSessionCompatApi21.sendSessionEvent(mSessionObj, event, extras);
183924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
184024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
184124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        @Override
184224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public void release() {
184324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            MediaSessionCompatApi21.release(mSessionObj);
184424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
184524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
184624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        @Override
184724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public Token getSessionToken() {
184824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            return mToken;
184924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
185024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
185124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        @Override
185224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public void setPlaybackState(PlaybackStateCompat state) {
185324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            MediaSessionCompatApi21.setPlaybackState(mSessionObj, state.getPlaybackState());
185424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
185524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
185624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        @Override
185724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public void setMetadata(MediaMetadataCompat metadata) {
185824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            MediaSessionCompatApi21.setMetadata(mSessionObj, metadata.getMediaMetadata());
185924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
186024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
186124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        @Override
186285d539daa11f9f7bd61ecb8ebb4d43536c02a736RoboErik        public void setSessionActivity(PendingIntent pi) {
186385d539daa11f9f7bd61ecb8ebb4d43536c02a736RoboErik            MediaSessionCompatApi21.setSessionActivity(mSessionObj, pi);
186485d539daa11f9f7bd61ecb8ebb4d43536c02a736RoboErik        }
186585d539daa11f9f7bd61ecb8ebb4d43536c02a736RoboErik
186685d539daa11f9f7bd61ecb8ebb4d43536c02a736RoboErik        @Override
1867ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik        public void setMediaButtonReceiver(PendingIntent mbr) {
1868ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik            mMediaButtonIntent = mbr;
1869ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik            MediaSessionCompatApi21.setMediaButtonReceiver(mSessionObj, mbr);
1870ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik        }
1871ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik
1872ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik        @Override
1873ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik        public void setQueue(List<QueueItem> queue) {
1874ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik            List<Object> queueObjs = null;
1875ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik            if (queue != null) {
1876ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik                queueObjs = new ArrayList<Object>();
1877ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik                for (QueueItem item : queue) {
1878ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik                    queueObjs.add(item.getQueueItem());
1879ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik                }
1880ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik            }
1881ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik            MediaSessionCompatApi21.setQueue(mSessionObj, queueObjs);
1882ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik        }
1883ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik
1884ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik        @Override
1885ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik        public void setQueueTitle(CharSequence title) {
1886ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik            MediaSessionCompatApi21.setQueueTitle(mSessionObj, title);
1887ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik        }
1888ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik
1889ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik        @Override
1890ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik        public void setRatingType(int type) {
1891ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik            if (android.os.Build.VERSION.SDK_INT < 22) {
1892ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik                // TODO figure out 21 implementation
1893ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik            } else {
1894ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik                MediaSessionCompatApi22.setRatingType(mSessionObj, type);
1895ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik            }
1896ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik        }
1897ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik
1898ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik        @Override
1899ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik        public void setExtras(Bundle extras) {
1900ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik            MediaSessionCompatApi21.setExtras(mSessionObj, extras);
1901ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik        }
1902ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik
1903ceb8bf5e5cce7a37736981e626c4be416378767bRoboErik        @Override
190424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public Object getMediaSession() {
190524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            return mSessionObj;
190624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
19075c9469e010106467791b47b0fa83efda84491a21RoboErik
19085c9469e010106467791b47b0fa83efda84491a21RoboErik        @Override
19095c9469e010106467791b47b0fa83efda84491a21RoboErik        public Object getRemoteControlClient() {
19105c9469e010106467791b47b0fa83efda84491a21RoboErik            return null;
19115c9469e010106467791b47b0fa83efda84491a21RoboErik        }
191224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    }
191324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown}
1914