124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown/*
224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown * Copyright (C) 2014 The Android Open Source Project
324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown *
424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown * Licensed under the Apache License, Version 2.0 (the "License");
524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown * you may not use this file except in compliance with the License.
624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown * You may obtain a copy of the License at
724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown *
824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown *      http://www.apache.org/licenses/LICENSE-2.0
924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown *
1024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown * Unless required by applicable law or agreed to in writing, software
1124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown * distributed under the License is distributed on an "AS IS" BASIS,
1224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown * See the License for the specific language governing permissions and
1424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown * limitations under the License.
1524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown */
1624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
1724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brownpackage android.support.v4.media.session;
1824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
19aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErikimport android.app.PendingIntent;
2024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brownimport android.content.Context;
21aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErikimport android.media.AudioManager;
22aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErikimport android.net.Uri;
2324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brownimport android.os.Bundle;
2424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brownimport android.os.Handler;
25e49860b0f76d8336c1d41831ed370b0ff94278efRoboErikimport android.os.IBinder;
26e49860b0f76d8336c1d41831ed370b0ff94278efRoboErikimport android.os.Looper;
27e49860b0f76d8336c1d41831ed370b0ff94278efRoboErikimport android.os.Message;
2824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brownimport android.os.RemoteException;
2924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brownimport android.os.ResultReceiver;
3024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brownimport android.support.v4.media.MediaMetadataCompat;
3124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brownimport android.support.v4.media.RatingCompat;
3224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brownimport android.support.v4.media.VolumeProviderCompat;
33e49860b0f76d8336c1d41831ed370b0ff94278efRoboErikimport android.support.v4.media.session.MediaSessionCompat.QueueItem;
34aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErikimport android.support.v4.media.session.PlaybackStateCompat.CustomAction;
3524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brownimport android.text.TextUtils;
36e49860b0f76d8336c1d41831ed370b0ff94278efRoboErikimport android.util.Log;
3724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brownimport android.view.KeyEvent;
3824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
39aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErikimport java.util.ArrayList;
40aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErikimport java.util.List;
41aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik
4224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown/**
4324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown * Allows an app to interact with an ongoing media session. Media buttons and
4424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown * other commands can be sent to the session. A callback may be registered to
4524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown * receive updates from the session, such as metadata and play state changes.
4624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown * <p>
4724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown * A MediaController can be created if you have a {@link MediaSessionCompat.Token}
4824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown * from the session owner.
4924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown * <p>
5024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown * MediaController objects are thread-safe.
5124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown * <p>
5224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown * This is a helper for accessing features in {@link android.media.session.MediaSession}
5324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown * introduced after API level 4 in a backwards compatible fashion.
5424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown */
5524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brownpublic final class MediaControllerCompat {
56e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik    private static final String TAG = "MediaControllerCompat";
57e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
5824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    private final MediaControllerImpl mImpl;
5994be6100218126ce6a08bf1f56209578500b361fRoboErik    private final MediaSessionCompat.Token mToken;
6024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
6124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    /**
6224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * Creates a media controller from a session.
6324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     *
6424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * @param session The session to be controlled.
6524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     */
6624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    public MediaControllerCompat(Context context, MediaSessionCompat session) {
6724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        if (session == null) {
6824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            throw new IllegalArgumentException("session must not be null");
6924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
7094be6100218126ce6a08bf1f56209578500b361fRoboErik        mToken = session.getSessionToken();
7124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
7224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        if (android.os.Build.VERSION.SDK_INT >= 21) {
7324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            mImpl = new MediaControllerImplApi21(context, session);
7424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        } else {
75e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            mImpl = new MediaControllerImplBase(mToken);
7624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
7724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    }
7824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
7924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    /**
8024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * Creates a media controller from a session token which may have
8124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * been obtained from another process.
8224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     *
8324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * @param sessionToken The token of the session to be controlled.
8424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * @throws RemoteException if the session is not accessible.
8524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     */
8624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    public MediaControllerCompat(Context context, MediaSessionCompat.Token sessionToken)
8724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            throws RemoteException {
8824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        if (sessionToken == null) {
8924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            throw new IllegalArgumentException("sessionToken must not be null");
9024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
9194be6100218126ce6a08bf1f56209578500b361fRoboErik        mToken = sessionToken;
9224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
9324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        if (android.os.Build.VERSION.SDK_INT >= 21) {
9424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            mImpl = new MediaControllerImplApi21(context, sessionToken);
9524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        } else {
96e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            mImpl = new MediaControllerImplBase(mToken);
9724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
9824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    }
9924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
10024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    /**
10124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * Get a {@link TransportControls} instance for this session.
10224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     *
10324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * @return A controls instance
10424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     */
10524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    public TransportControls getTransportControls() {
10624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        return mImpl.getTransportControls();
10724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    }
10824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
10924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    /**
11024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * Send the specified media button event to the session. Only media keys can
11124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * be sent by this method, other keys will be ignored.
11224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     *
11324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * @param keyEvent The media button event to dispatch.
11424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * @return true if the event was sent to the session, false otherwise.
11524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     */
11624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    public boolean dispatchMediaButtonEvent(KeyEvent keyEvent) {
11724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        if (keyEvent == null) {
11824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            throw new IllegalArgumentException("KeyEvent may not be null");
11924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
12024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        return mImpl.dispatchMediaButtonEvent(keyEvent);
12124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    }
12224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
12324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    /**
12424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * Get the current playback state for this session.
12524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     *
12624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * @return The current PlaybackState or null
12724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     */
12824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    public PlaybackStateCompat getPlaybackState() {
12924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        return mImpl.getPlaybackState();
13024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    }
13124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
13224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    /**
13324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * Get the current metadata for this session.
13424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     *
13524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * @return The current MediaMetadata or null.
13624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     */
13724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    public MediaMetadataCompat getMetadata() {
13824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        return mImpl.getMetadata();
13924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    }
14024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
14124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    /**
142aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik     * Get the current play queue for this session if one is set. If you only
143aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik     * care about the current item {@link #getMetadata()} should be used.
144aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik     *
145aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik     * @return The current play queue or null.
146aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik     */
147aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik    public List<MediaSessionCompat.QueueItem> getQueue() {
148aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        return mImpl.getQueue();
149aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik    }
150aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik
151aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik    /**
152aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik     * Get the queue title for this session.
153aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik     */
154aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik    public CharSequence getQueueTitle() {
155aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        return mImpl.getQueueTitle();
156aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik    }
157aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik
158aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik    /**
159aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik     * Get the extras for this session.
160aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik     */
161aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik    public Bundle getExtras() {
162aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        return mImpl.getExtras();
163aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik    }
164aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik
165aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik    /**
16624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * Get the rating type supported by the session. One of:
16724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * <ul>
16824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * <li>{@link RatingCompat#RATING_NONE}</li>
16924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * <li>{@link RatingCompat#RATING_HEART}</li>
17024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * <li>{@link RatingCompat#RATING_THUMB_UP_DOWN}</li>
17124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * <li>{@link RatingCompat#RATING_3_STARS}</li>
17224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * <li>{@link RatingCompat#RATING_4_STARS}</li>
17324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * <li>{@link RatingCompat#RATING_5_STARS}</li>
17424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * <li>{@link RatingCompat#RATING_PERCENTAGE}</li>
17524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * </ul>
17624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     *
17724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * @return The supported rating type
17824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     */
17924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    public int getRatingType() {
18024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        return mImpl.getRatingType();
18124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    }
18224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
18324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    /**
184aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik     * Get the flags for this session. Flags are defined in
185aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik     * {@link MediaSessionCompat}.
186aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik     *
187aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik     * @return The current set of flags for the session.
188aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik     */
189aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik    public long getFlags() {
190aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        return mImpl.getFlags();
191aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik    }
192aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik
193aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik    /**
194312f13dea7b4a9229dff784c6e94b0ec0c722b74RoboErik     * Get the current playback info for this session.
19524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     *
196312f13dea7b4a9229dff784c6e94b0ec0c722b74RoboErik     * @return The current playback info or null.
19724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     */
198312f13dea7b4a9229dff784c6e94b0ec0c722b74RoboErik    public PlaybackInfo getPlaybackInfo() {
199312f13dea7b4a9229dff784c6e94b0ec0c722b74RoboErik        return mImpl.getPlaybackInfo();
20024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    }
20124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
20224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    /**
203aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik     * Get an intent for launching UI associated with this session if one
204aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik     * exists.
205aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik     *
206aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik     * @return A {@link PendingIntent} to launch UI or null.
207aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik     */
208aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik    public PendingIntent getSessionActivity() {
209aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        return mImpl.getSessionActivity();
210aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik    }
211aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik
212aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik    /**
21394be6100218126ce6a08bf1f56209578500b361fRoboErik     * Get the token for the session this controller is connected to.
21494be6100218126ce6a08bf1f56209578500b361fRoboErik     *
21594be6100218126ce6a08bf1f56209578500b361fRoboErik     * @return The session's token.
21694be6100218126ce6a08bf1f56209578500b361fRoboErik     */
21794be6100218126ce6a08bf1f56209578500b361fRoboErik    public MediaSessionCompat.Token getSessionToken() {
21894be6100218126ce6a08bf1f56209578500b361fRoboErik        return mToken;
21994be6100218126ce6a08bf1f56209578500b361fRoboErik    }
22094be6100218126ce6a08bf1f56209578500b361fRoboErik
22194be6100218126ce6a08bf1f56209578500b361fRoboErik    /**
222aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik     * Set the volume of the output this session is playing on. The command will
223aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik     * be ignored if it does not support
224aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik     * {@link VolumeProviderCompat#VOLUME_CONTROL_ABSOLUTE}. The flags in
225aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik     * {@link AudioManager} may be used to affect the handling.
226aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik     *
227aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik     * @see #getPlaybackInfo()
228aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik     * @param value The value to set it to, between 0 and the reported max.
229aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik     * @param flags Flags from {@link AudioManager} to include with the volume
230aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik     *            request.
231aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik     */
232aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik    public void setVolumeTo(int value, int flags) {
233aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        mImpl.setVolumeTo(value, flags);
234aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik    }
235aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik
236aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik    /**
237aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik     * Adjust the volume of the output this session is playing on. The direction
238aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik     * must be one of {@link AudioManager#ADJUST_LOWER},
239aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik     * {@link AudioManager#ADJUST_RAISE}, or {@link AudioManager#ADJUST_SAME}.
240aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik     * The command will be ignored if the session does not support
241aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik     * {@link VolumeProviderCompat#VOLUME_CONTROL_RELATIVE} or
242aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik     * {@link VolumeProviderCompat#VOLUME_CONTROL_ABSOLUTE}. The flags in
243aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik     * {@link AudioManager} may be used to affect the handling.
244aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik     *
245aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik     * @see #getPlaybackInfo()
246aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik     * @param direction The direction to adjust the volume in.
247aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik     * @param flags Any flags to pass with the command.
248aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik     */
249aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik    public void adjustVolume(int direction, int flags) {
250aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        mImpl.adjustVolume(direction, flags);
251aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik    }
252aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik
253aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik    /**
25424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * Adds a callback to receive updates from the Session. Updates will be
25524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * posted on the caller's thread.
25624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     *
25724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * @param callback The callback object, must not be null.
25824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     */
25916ac83bebda2a19930b9d692789f3b507c49951bRoboErik    public void registerCallback(Callback callback) {
26016ac83bebda2a19930b9d692789f3b507c49951bRoboErik        registerCallback(callback, null);
26124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    }
26224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
26324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    /**
26424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * Adds a callback to receive updates from the session. Updates will be
26524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * posted on the specified handler's thread.
26624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     *
26724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * @param callback The callback object, must not be null.
26824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * @param handler The handler to post updates on. If null the callers thread
26924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     *            will be used.
27024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     */
27116ac83bebda2a19930b9d692789f3b507c49951bRoboErik    public void registerCallback(Callback callback, Handler handler) {
27224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        if (callback == null) {
27324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            throw new IllegalArgumentException("callback cannot be null");
27424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
27524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        if (handler == null) {
27624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            handler = new Handler();
27724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
27816ac83bebda2a19930b9d692789f3b507c49951bRoboErik        mImpl.registerCallback(callback, handler);
27924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    }
28024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
28124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    /**
28224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * Stop receiving updates on the specified callback. If an update has
28324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * already been posted you may still receive it after calling this method.
28424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     *
28524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * @param callback The callback to remove
28624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     */
28716ac83bebda2a19930b9d692789f3b507c49951bRoboErik    public void unregisterCallback(Callback callback) {
28824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        if (callback == null) {
28924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            throw new IllegalArgumentException("callback cannot be null");
29024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
29116ac83bebda2a19930b9d692789f3b507c49951bRoboErik        mImpl.unregisterCallback(callback);
29224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    }
29324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
29424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    /**
29524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * Sends a generic command to the session. It is up to the session creator
29624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * to decide what commands and parameters they will support. As such,
29724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * commands should only be sent to sessions that the controller owns.
29824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     *
29924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * @param command The command to send
30024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * @param params Any parameters to include with the command
30124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * @param cb The callback to receive the result on
30224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     */
303b530c89bba371d2d575f10480b2e90914b0d3f3fGabriel Peal    public void sendCommand(String command, Bundle params, ResultReceiver cb) {
30424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        if (TextUtils.isEmpty(command)) {
30524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            throw new IllegalArgumentException("command cannot be null or empty");
30624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
307b530c89bba371d2d575f10480b2e90914b0d3f3fGabriel Peal        mImpl.sendCommand(command, params, cb);
30824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    }
30924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
31024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    /**
311aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik     * Get the session owner's package name.
312aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik     *
313aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik     * @return The package name of of the session owner.
314aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik     */
315aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik    public String getPackageName() {
316aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        return mImpl.getPackageName();
317aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik    }
318aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik
319aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik    /**
320aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik     * Gets the underlying framework
321aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik     * {@link android.media.session.MediaController} object.
32224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * <p>
32324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * This method is only supported on API 21+.
32424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * </p>
32524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     *
326aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik     * @return The underlying {@link android.media.session.MediaController}
327aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik     *         object, or null if none.
32824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     */
32924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    public Object getMediaController() {
33024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        return mImpl.getMediaController();
33124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    }
33224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
33324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    /**
33424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * Callback for receiving updates on from the session. A Callback can be
33516ac83bebda2a19930b9d692789f3b507c49951bRoboErik     * registered using {@link #registerCallback}
33624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     */
337e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik    public static abstract class Callback implements IBinder.DeathRecipient {
338e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        private final Object mCallbackObj;
339e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        private MessageHandler mHandler;
340e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
341e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        private boolean mRegistered = false;
34224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
34324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public Callback() {
34424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            if (android.os.Build.VERSION.SDK_INT >= 21) {
34524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown                mCallbackObj = MediaControllerCompatApi21.createCallback(new StubApi21());
34624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            } else {
347e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                mCallbackObj = new StubCompat();
34824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            }
34924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
35024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
35124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        /**
35223138c4b9be07abdab0cfdde2c62186359c9e7faRoboErik         * Override to handle the session being destroyed. The session is no
35323138c4b9be07abdab0cfdde2c62186359c9e7faRoboErik         * longer valid after this call and calls to it will be ignored.
35423138c4b9be07abdab0cfdde2c62186359c9e7faRoboErik         */
35523138c4b9be07abdab0cfdde2c62186359c9e7faRoboErik        public void onSessionDestroyed() {
35623138c4b9be07abdab0cfdde2c62186359c9e7faRoboErik        }
35723138c4b9be07abdab0cfdde2c62186359c9e7faRoboErik
35823138c4b9be07abdab0cfdde2c62186359c9e7faRoboErik        /**
35924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * Override to handle custom events sent by the session owner without a
36024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * specified interface. Controllers should only handle these for
36124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * sessions they own.
36224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         *
36324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * @param event The event from the session.
36424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * @param extras Optional parameters for the event.
36524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         */
36624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public void onSessionEvent(String event, Bundle extras) {
36724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
36824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
36924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        /**
37024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * Override to handle changes in playback state.
37124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         *
37224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * @param state The new playback state of the session
37324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         */
37424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public void onPlaybackStateChanged(PlaybackStateCompat state) {
37524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
37624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
37724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        /**
37824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * Override to handle changes to the current metadata.
37924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         *
38024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * @param metadata The current metadata for the session or null if none.
38124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * @see MediaMetadata
38224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         */
38324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public void onMetadataChanged(MediaMetadataCompat metadata) {
38424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
38524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
386aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        /**
387aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         * Override to handle changes to items in the queue.
388aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         *
389aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         * @see MediaSessionCompat.QueueItem
390aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         * @param queue A list of items in the current play queue. It should
391aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         *            include the currently playing item as well as previous and
392aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         *            upcoming items if applicable.
393aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         */
394aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        public void onQueueChanged(List<MediaSessionCompat.QueueItem> queue) {
395aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        }
396aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik
397aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        /**
398aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         * Override to handle changes to the queue title.
399aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         *
400aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         * @param title The title that should be displayed along with the play
401aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         *            queue such as "Now Playing". May be null if there is no
402aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         *            such title.
403aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         */
404aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        public void onQueueTitleChanged(CharSequence title) {
405aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        }
406aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik
407aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        /**
408aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         * Override to handle chagnes to the {@link MediaSessionCompat} extras.
409aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         *
410aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         * @param extras The extras that can include other information
411aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         *            associated with the {@link MediaSessionCompat}.
412aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         */
413aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        public void onExtrasChanged(Bundle extras) {
414aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        }
415aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik
416aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        /**
417aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         * Override to handle changes to the audio info.
418aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         *
419aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         * @param info The current audio info for this session.
420aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         */
421aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        public void onAudioInfoChanged(PlaybackInfo info) {
422aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        }
423aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik
424e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        @Override
425e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        public void binderDied() {
426e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            onSessionDestroyed();
427e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        }
428e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
429e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        /**
430e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik         * Set the handler to use for pre 21 callbacks.
431e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik         */
432e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        private void setHandler(Handler handler) {
433e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            mHandler = new MessageHandler(handler.getLooper());
434e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        }
435e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
43624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        private class StubApi21 implements MediaControllerCompatApi21.Callback {
43724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            @Override
43823138c4b9be07abdab0cfdde2c62186359c9e7faRoboErik            public void onSessionDestroyed() {
43923138c4b9be07abdab0cfdde2c62186359c9e7faRoboErik                Callback.this.onSessionDestroyed();
44023138c4b9be07abdab0cfdde2c62186359c9e7faRoboErik            }
44123138c4b9be07abdab0cfdde2c62186359c9e7faRoboErik
44223138c4b9be07abdab0cfdde2c62186359c9e7faRoboErik            @Override
44324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            public void onSessionEvent(String event, Bundle extras) {
44424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown                Callback.this.onSessionEvent(event, extras);
44524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            }
44624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
44724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            @Override
44824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            public void onPlaybackStateChanged(Object stateObj) {
44924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown                Callback.this.onPlaybackStateChanged(
45024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown                        PlaybackStateCompat.fromPlaybackState(stateObj));
45124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            }
45224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
45324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            @Override
45424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            public void onMetadataChanged(Object metadataObj) {
45524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown                Callback.this.onMetadataChanged(
45624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown                        MediaMetadataCompat.fromMediaMetadata(metadataObj));
45724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            }
45824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
459e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
460e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        private class StubCompat extends IMediaControllerCallback.Stub {
461e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
462e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            @Override
463e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            public void onEvent(String event, Bundle extras) throws RemoteException {
464e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                mHandler.post(MessageHandler.MSG_EVENT, event, extras);
465e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
466e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
467e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            @Override
468e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            public void onSessionDestroyed() throws RemoteException {
469e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                mHandler.post(MessageHandler.MSG_DESTROYED, null, null);
470e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
471e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
472e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            @Override
473e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            public void onPlaybackStateChanged(PlaybackStateCompat state) throws RemoteException {
474e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                mHandler.post(MessageHandler.MSG_UPDATE_PLAYBACK_STATE, state, null);
475e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
476e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
477e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            @Override
478e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            public void onMetadataChanged(MediaMetadataCompat metadata) throws RemoteException {
479e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                mHandler.post(MessageHandler.MSG_UPDATE_METADATA, metadata, null);
480e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
481e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
482e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            @Override
483e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            public void onQueueChanged(List<QueueItem> queue) throws RemoteException {
484e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                mHandler.post(MessageHandler.MSG_UPDATE_QUEUE, queue, null);
485e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
486e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
487e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            @Override
488e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            public void onQueueTitleChanged(CharSequence title) throws RemoteException {
489e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                mHandler.post(MessageHandler.MSG_UPDATE_QUEUE_TITLE, title, null);
490e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
491e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
492e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            @Override
493e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            public void onExtrasChanged(Bundle extras) throws RemoteException {
494e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                mHandler.post(MessageHandler.MSG_UPDATE_EXTRAS, extras, null);
495e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
496e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
497e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            @Override
498e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            public void onVolumeInfoChanged(ParcelableVolumeInfo info) throws RemoteException {
499e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                PlaybackInfo pi = null;
500e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                if (info != null) {
501e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                    pi = new PlaybackInfo(info.volumeType, info.audioStream, info.controlType,
502e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                            info.maxVolume, info.currentVolume);
503e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                }
504e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                mHandler.post(MessageHandler.MSG_UPDATE_VOLUME, pi, null);
505e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
506e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        }
507e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
508e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        private class MessageHandler extends Handler {
509e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            private static final int MSG_EVENT = 1;
510e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            private static final int MSG_UPDATE_PLAYBACK_STATE = 2;
511e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            private static final int MSG_UPDATE_METADATA = 3;
512e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            private static final int MSG_UPDATE_VOLUME = 4;
513e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            private static final int MSG_UPDATE_QUEUE = 5;
514e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            private static final int MSG_UPDATE_QUEUE_TITLE = 6;
515e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            private static final int MSG_UPDATE_EXTRAS = 7;
516e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            private static final int MSG_DESTROYED = 8;
517e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
518e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            public MessageHandler(Looper looper) {
519e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                super(looper);
520e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
521e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
522e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            @Override
523e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            public void handleMessage(Message msg) {
524e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                if (!mRegistered) {
525e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                    return;
526e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                }
527e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                switch (msg.what) {
528e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                    case MSG_EVENT:
529e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                        onSessionEvent((String) msg.obj, msg.getData());
530e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                        break;
531e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                    case MSG_UPDATE_PLAYBACK_STATE:
532e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                        onPlaybackStateChanged((PlaybackStateCompat) msg.obj);
533e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                        break;
534e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                    case MSG_UPDATE_METADATA:
535e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                        onMetadataChanged((MediaMetadataCompat) msg.obj);
536e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                        break;
537e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                    case MSG_UPDATE_QUEUE:
538e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                        onQueueChanged((List<MediaSessionCompat.QueueItem>) msg.obj);
539e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                        break;
540e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                    case MSG_UPDATE_QUEUE_TITLE:
541e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                        onQueueTitleChanged((CharSequence) msg.obj);
542e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                        break;
543e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                    case MSG_UPDATE_EXTRAS:
544e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                        onExtrasChanged((Bundle) msg.obj);
545e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                        break;
546e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                    case MSG_UPDATE_VOLUME:
547e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                        onAudioInfoChanged((PlaybackInfo) msg.obj);
548e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                        break;
549e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                    case MSG_DESTROYED:
550e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                        onSessionDestroyed();
551e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                        break;
552e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                }
553e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
554e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
555e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            public void post(int what, Object obj, Bundle data) {
556e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                obtainMessage(what, obj).sendToTarget();
557e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
558e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        }
55924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    }
56024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
56124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    /**
56224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * Interface for controlling media playback on a session. This allows an app
56324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * to send media transport commands to the session.
56424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     */
56524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    public static abstract class TransportControls {
56624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        TransportControls() {
56724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
56824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
56924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        /**
57024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * Request that the player start its playback at its current position.
57124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         */
57224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public abstract void play();
57324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
57424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        /**
575aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         * Request that the player start playback for a specific {@link Uri}.
576aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         *
577aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         * @param mediaId The uri of the requested media.
578aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         * @param extras Optional extras that can include extra information
579aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         *            about the media item to be played.
580aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         */
581aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        public abstract void playFromMediaId(String mediaId, Bundle extras);
582aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik
583aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        /**
584aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         * Request that the player start playback for a specific search query.
585aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         * An empty or null query should be treated as a request to play any
586aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         * music.
587aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         *
588aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         * @param query The search query.
589aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         * @param extras Optional extras that can include extra information
590aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         *            about the query.
591aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         */
592aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        public abstract void playFromSearch(String query, Bundle extras);
593aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik
594aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        /**
595aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         * Play an item with a specific id in the play queue. If you specify an
596aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         * id that is not in the play queue, the behavior is undefined.
597aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         */
598aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        public abstract void skipToQueueItem(long id);
599aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik
600aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        /**
60124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * Request that the player pause its playback and stay at its current
60224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * position.
60324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         */
60424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public abstract void pause();
60524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
60624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        /**
60724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * Request that the player stop its playback; it may clear its state in
60824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * whatever way is appropriate.
60924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         */
61024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public abstract void stop();
61124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
61224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        /**
61324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * Move to a new location in the media stream.
61424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         *
61524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * @param pos Position to move to, in milliseconds.
61624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         */
61724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public abstract void seekTo(long pos);
61824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
61924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        /**
62024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * Start fast forwarding. If playback is already fast forwarding this
62124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * may increase the rate.
62224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         */
62324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public abstract void fastForward();
62424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
62524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        /**
62624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * Skip to the next item.
62724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         */
62824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public abstract void skipToNext();
62924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
63024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        /**
63124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * Start rewinding. If playback is already rewinding this may increase
63224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * the rate.
63324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         */
63424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public abstract void rewind();
63524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
63624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        /**
63724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * Skip to the previous item.
63824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         */
63924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public abstract void skipToPrevious();
64024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
64124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        /**
64224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * Rate the current content. This will cause the rating to be set for
64324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * the current user. The Rating type must match the type returned by
64424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * {@link #getRatingType()}.
64524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         *
64624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * @param rating The rating to set for the current content
64724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         */
64824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public abstract void setRating(RatingCompat rating);
649aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik
650aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        /**
651aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         * Send a custom action for the {@link MediaSessionCompat} to perform.
652aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         *
653aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         * @param customAction The action to perform.
654aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         * @param args Optional arguments to supply to the
655aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         *            {@link MediaSessionCompat} for this custom action.
656aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         */
657aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        public abstract void sendCustomAction(PlaybackStateCompat.CustomAction customAction,
658aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik                Bundle args);
659aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik
660aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        /**
661aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         * Send the id and args from a custom action for the
662aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         * {@link MediaSessionCompat} to perform.
663aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         *
664aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         * @see #sendCustomAction(PlaybackStateCompat.CustomAction action,
665aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         *      Bundle args)
666aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         * @param action The action identifier of the
667aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         *            {@link PlaybackStateCompat.CustomAction} as specified by
668aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         *            the {@link MediaSessionCompat}.
669aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         * @param args Optional arguments to supply to the
670aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         *            {@link MediaSessionCompat} for this custom action.
671aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         */
672aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        public abstract void sendCustomAction(String action, Bundle args);
67324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    }
67424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
67524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    /**
67624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * Holds information about the way volume is handled for this session.
67724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     */
678312f13dea7b4a9229dff784c6e94b0ec0c722b74RoboErik    public static final class PlaybackInfo {
679312f13dea7b4a9229dff784c6e94b0ec0c722b74RoboErik        /**
680312f13dea7b4a9229dff784c6e94b0ec0c722b74RoboErik         * The session uses local playback.
681312f13dea7b4a9229dff784c6e94b0ec0c722b74RoboErik         */
682312f13dea7b4a9229dff784c6e94b0ec0c722b74RoboErik        public static final int PLAYBACK_TYPE_LOCAL = 1;
683312f13dea7b4a9229dff784c6e94b0ec0c722b74RoboErik        /**
684312f13dea7b4a9229dff784c6e94b0ec0c722b74RoboErik         * The session uses remote playback.
685312f13dea7b4a9229dff784c6e94b0ec0c722b74RoboErik         */
686312f13dea7b4a9229dff784c6e94b0ec0c722b74RoboErik        public static final int PLAYBACK_TYPE_REMOTE = 2;
687312f13dea7b4a9229dff784c6e94b0ec0c722b74RoboErik
688312f13dea7b4a9229dff784c6e94b0ec0c722b74RoboErik        private final int mPlaybackType;
6891435afe32073dee10e721dfb6122ce6a194a6412RoboErik        // TODO update audio stream with AudioAttributes support version
69024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        private final int mAudioStream;
69124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        private final int mVolumeControl;
69224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        private final int mMaxVolume;
69324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        private final int mCurrentVolume;
69424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
695312f13dea7b4a9229dff784c6e94b0ec0c722b74RoboErik        PlaybackInfo(int type, int stream, int control, int max, int current) {
696312f13dea7b4a9229dff784c6e94b0ec0c722b74RoboErik            mPlaybackType = type;
69724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            mAudioStream = stream;
69824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            mVolumeControl = control;
69924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            mMaxVolume = max;
70024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            mCurrentVolume = current;
70124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
70224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
70324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        /**
70424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * Get the type of volume handling, either local or remote. One of:
70524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * <ul>
706312f13dea7b4a9229dff784c6e94b0ec0c722b74RoboErik         * <li>{@link PlaybackInfo#PLAYBACK_TYPE_LOCAL}</li>
707312f13dea7b4a9229dff784c6e94b0ec0c722b74RoboErik         * <li>{@link PlaybackInfo#PLAYBACK_TYPE_REMOTE}</li>
70824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * </ul>
70924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         *
71024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * @return The type of volume handling this session is using.
71124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         */
712312f13dea7b4a9229dff784c6e94b0ec0c722b74RoboErik        public int getPlaybackType() {
713312f13dea7b4a9229dff784c6e94b0ec0c722b74RoboErik            return mPlaybackType;
71424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
71524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
71624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        /**
71724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * Get the stream this is currently controlling volume on. When the volume
718312f13dea7b4a9229dff784c6e94b0ec0c722b74RoboErik         * type is {@link PlaybackInfo#PLAYBACK_TYPE_REMOTE} this value does not
71924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * have meaning and should be ignored.
72024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         *
72124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * @return The stream this session is playing on.
72224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         */
72324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public int getAudioStream() {
724aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik            // TODO switch to AudioAttributesCompat when it is added.
72524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            return mAudioStream;
72624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
72724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
72824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        /**
72924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * Get the type of volume control that can be used. One of:
73024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * <ul>
73124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * <li>{@link VolumeProviderCompat#VOLUME_CONTROL_ABSOLUTE}</li>
73224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * <li>{@link VolumeProviderCompat#VOLUME_CONTROL_RELATIVE}</li>
73324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * <li>{@link VolumeProviderCompat#VOLUME_CONTROL_FIXED}</li>
73424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * </ul>
73524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         *
73624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * @return The type of volume control that may be used with this
73724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         *         session.
73824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         */
73924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public int getVolumeControl() {
74024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            return mVolumeControl;
74124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
74224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
74324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        /**
74424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * Get the maximum volume that may be set for this session.
74524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         *
74624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * @return The maximum allowed volume where this session is playing.
74724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         */
74824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public int getMaxVolume() {
74924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            return mMaxVolume;
75024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
75124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
75224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        /**
75324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * Get the current volume for this session.
75424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         *
75524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * @return The current volume where this session is playing.
75624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         */
75724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public int getCurrentVolume() {
75824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            return mCurrentVolume;
75924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
76024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    }
76124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
76224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    interface MediaControllerImpl {
76316ac83bebda2a19930b9d692789f3b507c49951bRoboErik        void registerCallback(Callback callback, Handler handler);
76416ac83bebda2a19930b9d692789f3b507c49951bRoboErik
76516ac83bebda2a19930b9d692789f3b507c49951bRoboErik        void unregisterCallback(Callback callback);
76624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        boolean dispatchMediaButtonEvent(KeyEvent keyEvent);
76724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        TransportControls getTransportControls();
76824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        PlaybackStateCompat getPlaybackState();
76924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        MediaMetadataCompat getMetadata();
770aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik
771aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        List<MediaSessionCompat.QueueItem> getQueue();
772aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        CharSequence getQueueTitle();
773aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        Bundle getExtras();
77424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        int getRatingType();
775aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        long getFlags();
776312f13dea7b4a9229dff784c6e94b0ec0c722b74RoboErik        PlaybackInfo getPlaybackInfo();
777aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        PendingIntent getSessionActivity();
778aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik
779aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        void setVolumeTo(int value, int flags);
780aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        void adjustVolume(int direction, int flags);
781b530c89bba371d2d575f10480b2e90914b0d3f3fGabriel Peal        void sendCommand(String command, Bundle params, ResultReceiver cb);
782aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik
783aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        String getPackageName();
78424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        Object getMediaController();
78524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    }
78624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
78724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    static class MediaControllerImplBase implements MediaControllerImpl {
788e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        private MediaSessionCompat.Token mToken;
789e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        private IMediaSession mBinder;
790e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        private TransportControls mTransportControls;
791e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
792e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        public MediaControllerImplBase(MediaSessionCompat.Token token) {
793e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            mToken = token;
794e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            mBinder = IMediaSession.Stub.asInterface((IBinder) token.getToken());
795e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        }
796e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
79724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        @Override
79816ac83bebda2a19930b9d692789f3b507c49951bRoboErik        public void registerCallback(Callback callback, Handler handler) {
799e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            if (callback == null) {
800e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                throw new IllegalArgumentException("callback may not be null.");
801e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
802e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            try {
803e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                mBinder.asBinder().linkToDeath(callback, 0);
804e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                mBinder.registerCallbackListener((IMediaControllerCallback) callback.mCallbackObj);
805e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                callback.setHandler(handler);
806e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                callback.mRegistered = true;
807e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            } catch (RemoteException e) {
808e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                Log.e(TAG, "Dead object in registerCallback. " + e);
809e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                callback.onSessionDestroyed();
810e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
81124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
81224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
81324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        @Override
81416ac83bebda2a19930b9d692789f3b507c49951bRoboErik        public void unregisterCallback(Callback callback) {
815e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            if (callback == null) {
816e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                throw new IllegalArgumentException("callback may not be null.");
817e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
818e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            try {
819e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                mBinder.unregisterCallbackListener(
820e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                        (IMediaControllerCallback) callback.mCallbackObj);
821e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                mBinder.asBinder().unlinkToDeath(callback, 0);
822e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                callback.mRegistered = false;
823e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            } catch (RemoteException e) {
824e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                Log.e(TAG, "Dead object in unregisterCallback. " + e);
825e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
82624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
82724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
82824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        @Override
82924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public boolean dispatchMediaButtonEvent(KeyEvent event) {
830e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            if (event == null) {
831e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                throw new IllegalArgumentException("event may not be null.");
832e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
833e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            try {
834e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                mBinder.sendMediaButton(event);
835e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            } catch (RemoteException e) {
836e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                Log.e(TAG, "Dead object in dispatchMediaButtonEvent. " + e);
837e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
83824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            return false;
83924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
84024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
84124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        @Override
84224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public TransportControls getTransportControls() {
843e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            if (mTransportControls == null) {
844e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                mTransportControls = new TransportControlsBase(mBinder);
845e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
846e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
847e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            return mTransportControls;
84824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
84924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
85024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        @Override
85124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public PlaybackStateCompat getPlaybackState() {
852e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            try {
853e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                return mBinder.getPlaybackState();
854e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            } catch (RemoteException e) {
855e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                Log.e(TAG, "Dead object in getPlaybackState. " + e);
856e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
85724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            return null;
85824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
85924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
86024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        @Override
86124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public MediaMetadataCompat getMetadata() {
862e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            try {
863e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                return mBinder.getMetadata();
864e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            } catch (RemoteException e) {
865e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                Log.e(TAG, "Dead object in getMetadata. " + e);
866e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
86724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            return null;
86824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
86924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
87024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        @Override
871aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        public List<MediaSessionCompat.QueueItem> getQueue() {
872e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            try {
873e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                return mBinder.getQueue();
874e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            } catch (RemoteException e) {
875e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                Log.e(TAG, "Dead object in getQueue. " + e);
876e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
877aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik            return null;
878aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        }
879aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik
880aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        @Override
881aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        public CharSequence getQueueTitle() {
882e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            try {
883e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                return mBinder.getQueueTitle();
884e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            } catch (RemoteException e) {
885e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                Log.e(TAG, "Dead object in getQueueTitle. " + e);
886e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
887aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik            return null;
888aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        }
889aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik
890aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        @Override
891aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        public Bundle getExtras() {
892e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            try {
893e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                return mBinder.getExtras();
894e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            } catch (RemoteException e) {
895e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                Log.e(TAG, "Dead object in getExtras. " + e);
896e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
897aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik            return null;
898aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        }
899aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik
900aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        @Override
90124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public int getRatingType() {
902e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            try {
903e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                return mBinder.getRatingType();
904e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            } catch (RemoteException e) {
905e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                Log.e(TAG, "Dead object in getRatingType. " + e);
906e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
90724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            return 0;
90824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
90924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
91024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        @Override
911aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        public long getFlags() {
912e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            try {
913e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                return mBinder.getFlags();
914e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            } catch (RemoteException e) {
915e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                Log.e(TAG, "Dead object in getFlags. " + e);
916e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
917aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik            return 0;
918aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        }
919aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik
920aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        @Override
921312f13dea7b4a9229dff784c6e94b0ec0c722b74RoboErik        public PlaybackInfo getPlaybackInfo() {
922e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            try {
923e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                ParcelableVolumeInfo info = mBinder.getVolumeAttributes();
924e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                PlaybackInfo pi = new PlaybackInfo(info.volumeType, info.audioStream,
925e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                        info.controlType, info.maxVolume, info.currentVolume);
926e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                return pi;
927e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            } catch (RemoteException e) {
928e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                Log.e(TAG, "Dead object in getPlaybackInfo. " + e);
929e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
93024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            return null;
93124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
93224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
93324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        @Override
934aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        public PendingIntent getSessionActivity() {
935e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            try {
936e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                return mBinder.getLaunchPendingIntent();
937e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            } catch (RemoteException e) {
938e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                Log.e(TAG, "Dead object in getSessionActivity. " + e);
939e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
940aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik            return null;
941aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        }
942aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik
943aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        @Override
944aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        public void setVolumeTo(int value, int flags) {
945e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            try {
946e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                mBinder.setVolumeTo(value, flags, null);
947e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            } catch (RemoteException e) {
948e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                Log.e(TAG, "Dead object in setVolumeTo. " + e);
949e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
950aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        }
951aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik
952aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        @Override
953aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        public void adjustVolume(int direction, int flags) {
954e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            try {
955e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                mBinder.adjustVolume(direction, flags, null);
956e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            } catch (RemoteException e) {
957e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                Log.e(TAG, "Dead object in adjustVolume. " + e);
958e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
959aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        }
960aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik
961aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        @Override
962b530c89bba371d2d575f10480b2e90914b0d3f3fGabriel Peal        public void sendCommand(String command, Bundle params, ResultReceiver cb) {
963e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            try {
964e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                mBinder.sendCommand(command, params,
965e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                        new MediaSessionCompat.ResultReceiverWrapper(cb));
966e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            } catch (RemoteException e) {
967e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                Log.e(TAG, "Dead object in sendCommand. " + e);
968e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
96924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
97024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
97124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        @Override
972aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        public String getPackageName() {
973e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            try {
974e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                return mBinder.getPackageName();
975e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            } catch (RemoteException e) {
976e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                Log.e(TAG, "Dead object in getPackageName. " + e);
977e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
978aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik            return null;
979aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        }
980aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik
981aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        @Override
98224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public Object getMediaController() {
98324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            return null;
98424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
98524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    }
98624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
987e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik    static class TransportControlsBase extends TransportControls {
988e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        private IMediaSession mBinder;
989e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
990e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        public TransportControlsBase(IMediaSession binder) {
991e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            mBinder = binder;
992e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        }
993e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
994e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        @Override
995e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        public void play() {
996e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            try {
997e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                mBinder.play();
998e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            } catch (RemoteException e) {
999e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                Log.e(TAG, "Dead object in play. " + e);
1000e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
1001e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        }
1002e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
1003e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        @Override
1004e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        public void playFromMediaId(String mediaId, Bundle extras) {
1005e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            try {
1006e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                mBinder.playFromMediaId(mediaId, extras);
1007e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            } catch (RemoteException e) {
1008e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                Log.e(TAG, "Dead object in playFromMediaId. " + e);
1009e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
1010e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        }
1011e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
1012e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        @Override
1013e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        public void playFromSearch(String query, Bundle extras) {
1014e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            try {
1015e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                mBinder.playFromSearch(query, extras);
1016e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            } catch (RemoteException e) {
1017e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                Log.e(TAG, "Dead object in playFromSearch. " + e);
1018e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
1019e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        }
1020e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
1021e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        @Override
1022e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        public void skipToQueueItem(long id) {
1023e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            try {
1024e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                mBinder.skipToQueueItem(id);
1025e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            } catch (RemoteException e) {
1026e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                Log.e(TAG, "Dead object in skipToQueueItem. " + e);
1027e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
1028e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        }
1029e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
1030e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        @Override
1031e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        public void pause() {
1032e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            try {
1033e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                mBinder.pause();
1034e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            } catch (RemoteException e) {
1035e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                Log.e(TAG, "Dead object in pause. " + e);
1036e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
1037e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        }
1038e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
1039e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        @Override
1040e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        public void stop() {
1041e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            try {
1042e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                mBinder.stop();
1043e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            } catch (RemoteException e) {
1044e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                Log.e(TAG, "Dead object in stop. " + e);
1045e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
1046e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        }
1047e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
1048e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        @Override
1049e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        public void seekTo(long pos) {
1050e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            try {
1051e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                mBinder.seekTo(pos);
1052e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            } catch (RemoteException e) {
1053e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                Log.e(TAG, "Dead object in seekTo. " + e);
1054e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
1055e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        }
1056e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
1057e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        @Override
1058e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        public void fastForward() {
1059e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            try {
1060e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                mBinder.fastForward();
1061e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            } catch (RemoteException e) {
1062e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                Log.e(TAG, "Dead object in fastForward. " + e);
1063e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
1064e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        }
1065e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
1066e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        @Override
1067e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        public void skipToNext() {
1068e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            try {
1069e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                mBinder.next();
1070e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            } catch (RemoteException e) {
1071e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                Log.e(TAG, "Dead object in skipToNext. " + e);
1072e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
1073e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        }
1074e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
1075e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        @Override
1076e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        public void rewind() {
1077e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            try {
1078e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                mBinder.rewind();
1079e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            } catch (RemoteException e) {
1080e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                Log.e(TAG, "Dead object in rewind. " + e);
1081e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
1082e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        }
1083e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
1084e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        @Override
1085e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        public void skipToPrevious() {
1086e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            try {
1087e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                mBinder.previous();
1088e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            } catch (RemoteException e) {
1089e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                Log.e(TAG, "Dead object in skipToPrevious. " + e);
1090e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
1091e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        }
1092e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
1093e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        @Override
1094e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        public void setRating(RatingCompat rating) {
1095e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            try {
1096e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                mBinder.rate(rating);
1097e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            } catch (RemoteException e) {
1098e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                Log.e(TAG, "Dead object in setRating. " + e);
1099e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
1100e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        }
1101e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
1102e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        @Override
1103e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        public void sendCustomAction(CustomAction customAction, Bundle args) {
1104e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            sendCustomAction(customAction.getAction(), args);
1105e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        }
1106e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
1107e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        @Override
1108e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        public void sendCustomAction(String action, Bundle args) {
1109e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            try {
1110e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                mBinder.sendCustomAction(action, args);
1111e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            } catch (RemoteException e) {
1112e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                Log.e(TAG, "Dead object in sendCustomAction. " + e);
1113e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
1114e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        }
1115e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik    }
1116e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
111724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    static class MediaControllerImplApi21 implements MediaControllerImpl {
111824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        private final Object mControllerObj;
111924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
112024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public MediaControllerImplApi21(Context context, MediaSessionCompat session) {
11215c41750574ba65da432b69f89cd32dc356281005RoboErik            mControllerObj = MediaControllerCompatApi21.fromToken(context,
112224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown                    session.getSessionToken().getToken());
112324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
112424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
112524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public MediaControllerImplApi21(Context context, MediaSessionCompat.Token sessionToken)
112624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown                throws RemoteException {
11275c41750574ba65da432b69f89cd32dc356281005RoboErik            mControllerObj = MediaControllerCompatApi21.fromToken(context,
112824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown                    sessionToken.getToken());
112924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            if (mControllerObj == null) throw new RemoteException();
113024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
113124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
113224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        @Override
113316ac83bebda2a19930b9d692789f3b507c49951bRoboErik        public void registerCallback(Callback callback, Handler handler) {
113416ac83bebda2a19930b9d692789f3b507c49951bRoboErik            MediaControllerCompatApi21.registerCallback(mControllerObj, callback.mCallbackObj, handler);
113524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
113624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
113724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        @Override
113816ac83bebda2a19930b9d692789f3b507c49951bRoboErik        public void unregisterCallback(Callback callback) {
113916ac83bebda2a19930b9d692789f3b507c49951bRoboErik            MediaControllerCompatApi21.unregisterCallback(mControllerObj, callback.mCallbackObj);
114024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
114124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
114224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        @Override
114324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public boolean dispatchMediaButtonEvent(KeyEvent event) {
114424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            return MediaControllerCompatApi21.dispatchMediaButtonEvent(mControllerObj, event);
114524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
114624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
114724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        @Override
114824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public TransportControls getTransportControls() {
11491435afe32073dee10e721dfb6122ce6a194a6412RoboErik            Object controlsObj = MediaControllerCompatApi21.getTransportControls(mControllerObj);
115024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            return controlsObj != null ? new TransportControlsApi21(controlsObj) : null;
115124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
115224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
115324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        @Override
115424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public PlaybackStateCompat getPlaybackState() {
115524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            Object stateObj = MediaControllerCompatApi21.getPlaybackState(mControllerObj);
115624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            return stateObj != null ? PlaybackStateCompat.fromPlaybackState(stateObj) : null;
115724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
115824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
115924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        @Override
116024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public MediaMetadataCompat getMetadata() {
116124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            Object metadataObj = MediaControllerCompatApi21.getMetadata(mControllerObj);
116224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            return metadataObj != null ? MediaMetadataCompat.fromMediaMetadata(metadataObj) : null;
116324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
116424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
116524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        @Override
1166aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        public List<MediaSessionCompat.QueueItem> getQueue() {
1167aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik            List<Object> queueObjs = MediaControllerCompatApi21.getQueue(mControllerObj);
1168aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik            if (queueObjs == null) {
1169aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik                return null;
1170aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik            }
1171aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik            List<MediaSessionCompat.QueueItem> queue =
1172aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik                    new ArrayList<MediaSessionCompat.QueueItem>();
1173aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik            for (Object item : queueObjs) {
1174aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik                queue.add(MediaSessionCompat.QueueItem.obtain(item));
1175aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik            }
1176aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik            return queue;
1177aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        }
1178aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik
1179aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        @Override
1180aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        public CharSequence getQueueTitle() {
1181aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik            return MediaControllerCompatApi21.getQueueTitle(mControllerObj);
1182aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        }
1183aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik
1184aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        @Override
1185aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        public Bundle getExtras() {
1186aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik            return MediaControllerCompatApi21.getExtras(mControllerObj);
1187aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        }
1188aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik
1189aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        @Override
119024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public int getRatingType() {
119124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            return MediaControllerCompatApi21.getRatingType(mControllerObj);
119224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
119324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
119424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        @Override
1195aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        public long getFlags() {
1196aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik            return MediaControllerCompatApi21.getFlags(mControllerObj);
1197aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        }
1198aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik
1199aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        @Override
1200312f13dea7b4a9229dff784c6e94b0ec0c722b74RoboErik        public PlaybackInfo getPlaybackInfo() {
1201312f13dea7b4a9229dff784c6e94b0ec0c722b74RoboErik            Object volumeInfoObj = MediaControllerCompatApi21.getPlaybackInfo(mControllerObj);
1202312f13dea7b4a9229dff784c6e94b0ec0c722b74RoboErik            return volumeInfoObj != null ? new PlaybackInfo(
1203312f13dea7b4a9229dff784c6e94b0ec0c722b74RoboErik                    MediaControllerCompatApi21.PlaybackInfo.getPlaybackType(volumeInfoObj),
1204312f13dea7b4a9229dff784c6e94b0ec0c722b74RoboErik                    MediaControllerCompatApi21.PlaybackInfo.getLegacyAudioStream(volumeInfoObj),
1205312f13dea7b4a9229dff784c6e94b0ec0c722b74RoboErik                    MediaControllerCompatApi21.PlaybackInfo.getVolumeControl(volumeInfoObj),
1206312f13dea7b4a9229dff784c6e94b0ec0c722b74RoboErik                    MediaControllerCompatApi21.PlaybackInfo.getMaxVolume(volumeInfoObj),
1207312f13dea7b4a9229dff784c6e94b0ec0c722b74RoboErik                    MediaControllerCompatApi21.PlaybackInfo.getCurrentVolume(volumeInfoObj)) : null;
120824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
120924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
121024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        @Override
1211aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        public PendingIntent getSessionActivity() {
1212aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik            return MediaControllerCompatApi21.getSessionActivity(mControllerObj);
1213aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        }
1214aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik
1215aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        @Override
1216aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        public void setVolumeTo(int value, int flags) {
1217aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik            MediaControllerCompatApi21.setVolumeTo(mControllerObj, value, flags);
1218aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        }
1219aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik
1220aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        @Override
1221aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        public void adjustVolume(int direction, int flags) {
1222aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik            MediaControllerCompatApi21.adjustVolume(mControllerObj, direction, flags);
1223aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        }
1224aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik
1225aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        @Override
1226b530c89bba371d2d575f10480b2e90914b0d3f3fGabriel Peal        public void sendCommand(String command, Bundle params, ResultReceiver cb) {
1227b530c89bba371d2d575f10480b2e90914b0d3f3fGabriel Peal            MediaControllerCompatApi21.sendCommand(mControllerObj, command, params, cb);
122824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
122924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
123024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        @Override
1231aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        public String getPackageName() {
1232aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik            return MediaControllerCompatApi21.getPackageName(mControllerObj);
1233aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        }
1234aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik
1235aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        @Override
123624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public Object getMediaController() {
123724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            return mControllerObj;
123824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
123924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    }
124024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
124124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    static class TransportControlsApi21 extends TransportControls {
124224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        private final Object mControlsObj;
124324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
124424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public TransportControlsApi21(Object controlsObj) {
124524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            mControlsObj = controlsObj;
124624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
124724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
124824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        @Override
124924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public void play() {
125024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            MediaControllerCompatApi21.TransportControls.play(mControlsObj);
125124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
125224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
125324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        @Override
125424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public void pause() {
125524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            MediaControllerCompatApi21.TransportControls.pause(mControlsObj);
125624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
125724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
125824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        @Override
125924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public void stop() {
126024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            MediaControllerCompatApi21.TransportControls.stop(mControlsObj);
126124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
126224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
126324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        @Override
126424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public void seekTo(long pos) {
126524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            MediaControllerCompatApi21.TransportControls.seekTo(mControlsObj, pos);
126624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
126724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
126824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        @Override
126924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public void fastForward() {
127024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            MediaControllerCompatApi21.TransportControls.fastForward(mControlsObj);
127124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
127224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
127324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        @Override
127424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public void rewind() {
127524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            MediaControllerCompatApi21.TransportControls.rewind(mControlsObj);
127624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
127724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
127824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        @Override
127924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public void skipToNext() {
128024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            MediaControllerCompatApi21.TransportControls.skipToNext(mControlsObj);
128124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
128224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
128324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        @Override
128424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public void skipToPrevious() {
128524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            MediaControllerCompatApi21.TransportControls.skipToPrevious(mControlsObj);
128624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
128724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
128824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        @Override
128924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public void setRating(RatingCompat rating) {
129024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            MediaControllerCompatApi21.TransportControls.setRating(mControlsObj,
129124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown                    rating != null ? rating.getRating() : null);
129224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
1293aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik
1294aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        @Override
1295aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        public void playFromMediaId(String mediaId, Bundle extras) {
1296aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik            MediaControllerCompatApi21.TransportControls.playFromMediaId(mControlsObj, mediaId,
1297aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik                    extras);
1298aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        }
1299aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik
1300aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        @Override
1301aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        public void playFromSearch(String query, Bundle extras) {
1302aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik            MediaControllerCompatApi21.TransportControls.playFromSearch(mControlsObj, query,
1303aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik                    extras);
1304aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        }
1305aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik
1306aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        @Override
1307aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        public void skipToQueueItem(long id) {
1308aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik            MediaControllerCompatApi21.TransportControls.skipToQueueItem(mControlsObj, id);
1309aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        }
1310aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik
1311aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        @Override
1312aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        public void sendCustomAction(CustomAction customAction, Bundle args) {
1313aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik            MediaControllerCompatApi21.TransportControls.sendCustomAction(mControlsObj,
1314aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik                    customAction.getAction(), args);
1315aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        }
1316aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik
1317aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        @Override
1318aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        public void sendCustomAction(String action, Bundle args) {
1319aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik            MediaControllerCompatApi21.TransportControls.sendCustomAction(mControlsObj, action,
1320aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik                    args);
1321aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        }
132224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    }
132324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown}
1324