MediaControllerCompat.java revision b51f456b92aeb62d5aa9d67e1fb2725b2035fddd
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
72b51f456b92aeb62d5aa9d67e1fb2725b2035fdddIan Lake        if (android.os.Build.VERSION.SDK_INT >= 23) {
73b51f456b92aeb62d5aa9d67e1fb2725b2035fdddIan Lake            mImpl = new MediaControllerImplApi23(context, session);
74b51f456b92aeb62d5aa9d67e1fb2725b2035fdddIan Lake        } else if (android.os.Build.VERSION.SDK_INT >= 21) {
7524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            mImpl = new MediaControllerImplApi21(context, session);
7624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        } else {
77e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            mImpl = new MediaControllerImplBase(mToken);
7824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
7924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    }
8024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
8124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    /**
8224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * Creates a media controller from a session token which may have
8324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * been obtained from another process.
8424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     *
8524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * @param sessionToken The token of the session to be controlled.
8624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * @throws RemoteException if the session is not accessible.
8724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     */
8824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    public MediaControllerCompat(Context context, MediaSessionCompat.Token sessionToken)
8924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            throws RemoteException {
9024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        if (sessionToken == null) {
9124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            throw new IllegalArgumentException("sessionToken must not be null");
9224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
9394be6100218126ce6a08bf1f56209578500b361fRoboErik        mToken = sessionToken;
9424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
9524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        if (android.os.Build.VERSION.SDK_INT >= 21) {
9624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            mImpl = new MediaControllerImplApi21(context, sessionToken);
9724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        } else {
98e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            mImpl = new MediaControllerImplBase(mToken);
9924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
10024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    }
10124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
10224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    /**
10324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * Get a {@link TransportControls} instance for this session.
10424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     *
10524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * @return A controls instance
10624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     */
10724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    public TransportControls getTransportControls() {
10824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        return mImpl.getTransportControls();
10924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    }
11024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
11124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    /**
11224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * Send the specified media button event to the session. Only media keys can
11324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * be sent by this method, other keys will be ignored.
11424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     *
11524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * @param keyEvent The media button event to dispatch.
11624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * @return true if the event was sent to the session, false otherwise.
11724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     */
11824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    public boolean dispatchMediaButtonEvent(KeyEvent keyEvent) {
11924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        if (keyEvent == null) {
12024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            throw new IllegalArgumentException("KeyEvent may not be null");
12124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
12224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        return mImpl.dispatchMediaButtonEvent(keyEvent);
12324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    }
12424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
12524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    /**
12624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * Get the current playback state for this session.
12724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     *
12824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * @return The current PlaybackState or null
12924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     */
13024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    public PlaybackStateCompat getPlaybackState() {
13124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        return mImpl.getPlaybackState();
13224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    }
13324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
13424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    /**
13524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * Get the current metadata for this session.
13624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     *
13724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * @return The current MediaMetadata or null.
13824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     */
13924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    public MediaMetadataCompat getMetadata() {
14024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        return mImpl.getMetadata();
14124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    }
14224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
14324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    /**
144aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik     * Get the current play queue for this session if one is set. If you only
145aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik     * care about the current item {@link #getMetadata()} should be used.
146aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik     *
147aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik     * @return The current play queue or null.
148aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik     */
149aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik    public List<MediaSessionCompat.QueueItem> getQueue() {
150aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        return mImpl.getQueue();
151aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik    }
152aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik
153aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik    /**
154aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik     * Get the queue title for this session.
155aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik     */
156aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik    public CharSequence getQueueTitle() {
157aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        return mImpl.getQueueTitle();
158aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik    }
159aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik
160aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik    /**
161aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik     * Get the extras for this session.
162aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik     */
163aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik    public Bundle getExtras() {
164aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        return mImpl.getExtras();
165aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik    }
166aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik
167aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik    /**
16824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * Get the rating type supported by the session. One of:
16924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * <ul>
17024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * <li>{@link RatingCompat#RATING_NONE}</li>
17124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * <li>{@link RatingCompat#RATING_HEART}</li>
17224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * <li>{@link RatingCompat#RATING_THUMB_UP_DOWN}</li>
17324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * <li>{@link RatingCompat#RATING_3_STARS}</li>
17424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * <li>{@link RatingCompat#RATING_4_STARS}</li>
17524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * <li>{@link RatingCompat#RATING_5_STARS}</li>
17624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * <li>{@link RatingCompat#RATING_PERCENTAGE}</li>
17724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * </ul>
17824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     *
17924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * @return The supported rating type
18024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     */
18124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    public int getRatingType() {
18224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        return mImpl.getRatingType();
18324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    }
18424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
18524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    /**
186aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik     * Get the flags for this session. Flags are defined in
187aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik     * {@link MediaSessionCompat}.
188aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik     *
189aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik     * @return The current set of flags for the session.
190aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik     */
191aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik    public long getFlags() {
192aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        return mImpl.getFlags();
193aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik    }
194aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik
195aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik    /**
196312f13dea7b4a9229dff784c6e94b0ec0c722b74RoboErik     * Get the current playback info for this session.
19724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     *
198312f13dea7b4a9229dff784c6e94b0ec0c722b74RoboErik     * @return The current playback info or null.
19924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     */
200312f13dea7b4a9229dff784c6e94b0ec0c722b74RoboErik    public PlaybackInfo getPlaybackInfo() {
201312f13dea7b4a9229dff784c6e94b0ec0c722b74RoboErik        return mImpl.getPlaybackInfo();
20224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    }
20324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
20424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    /**
205aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik     * Get an intent for launching UI associated with this session if one
206aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik     * exists.
207aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik     *
208aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik     * @return A {@link PendingIntent} to launch UI or null.
209aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik     */
210aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik    public PendingIntent getSessionActivity() {
211aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        return mImpl.getSessionActivity();
212aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik    }
213aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik
214aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik    /**
21594be6100218126ce6a08bf1f56209578500b361fRoboErik     * Get the token for the session this controller is connected to.
21694be6100218126ce6a08bf1f56209578500b361fRoboErik     *
21794be6100218126ce6a08bf1f56209578500b361fRoboErik     * @return The session's token.
21894be6100218126ce6a08bf1f56209578500b361fRoboErik     */
21994be6100218126ce6a08bf1f56209578500b361fRoboErik    public MediaSessionCompat.Token getSessionToken() {
22094be6100218126ce6a08bf1f56209578500b361fRoboErik        return mToken;
22194be6100218126ce6a08bf1f56209578500b361fRoboErik    }
22294be6100218126ce6a08bf1f56209578500b361fRoboErik
22394be6100218126ce6a08bf1f56209578500b361fRoboErik    /**
224aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik     * Set the volume of the output this session is playing on. The command will
225aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik     * be ignored if it does not support
226aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik     * {@link VolumeProviderCompat#VOLUME_CONTROL_ABSOLUTE}. The flags in
227aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik     * {@link AudioManager} may be used to affect the handling.
228aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik     *
229aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik     * @see #getPlaybackInfo()
230aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik     * @param value The value to set it to, between 0 and the reported max.
231aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik     * @param flags Flags from {@link AudioManager} to include with the volume
232aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik     *            request.
233aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik     */
234aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik    public void setVolumeTo(int value, int flags) {
235aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        mImpl.setVolumeTo(value, flags);
236aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik    }
237aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik
238aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik    /**
239aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik     * Adjust the volume of the output this session is playing on. The direction
240aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik     * must be one of {@link AudioManager#ADJUST_LOWER},
241aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik     * {@link AudioManager#ADJUST_RAISE}, or {@link AudioManager#ADJUST_SAME}.
242aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik     * The command will be ignored if the session does not support
243aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik     * {@link VolumeProviderCompat#VOLUME_CONTROL_RELATIVE} or
244aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik     * {@link VolumeProviderCompat#VOLUME_CONTROL_ABSOLUTE}. The flags in
245aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik     * {@link AudioManager} may be used to affect the handling.
246aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik     *
247aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik     * @see #getPlaybackInfo()
248aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik     * @param direction The direction to adjust the volume in.
249aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik     * @param flags Any flags to pass with the command.
250aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik     */
251aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik    public void adjustVolume(int direction, int flags) {
252aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        mImpl.adjustVolume(direction, flags);
253aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik    }
254aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik
255aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik    /**
25624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * Adds a callback to receive updates from the Session. Updates will be
25724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * posted on the caller's thread.
25824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     *
25924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * @param callback The callback object, must not be null.
26024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     */
26116ac83bebda2a19930b9d692789f3b507c49951bRoboErik    public void registerCallback(Callback callback) {
26216ac83bebda2a19930b9d692789f3b507c49951bRoboErik        registerCallback(callback, null);
26324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    }
26424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
26524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    /**
26624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * Adds a callback to receive updates from the session. Updates will be
26724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * posted on the specified handler's thread.
26824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     *
26924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * @param callback The callback object, must not be null.
27024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * @param handler The handler to post updates on. If null the callers thread
27124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     *            will be used.
27224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     */
27316ac83bebda2a19930b9d692789f3b507c49951bRoboErik    public void registerCallback(Callback callback, Handler handler) {
27424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        if (callback == null) {
27524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            throw new IllegalArgumentException("callback cannot be null");
27624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
27724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        if (handler == null) {
27824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            handler = new Handler();
27924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
28016ac83bebda2a19930b9d692789f3b507c49951bRoboErik        mImpl.registerCallback(callback, handler);
28124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    }
28224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
28324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    /**
28424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * Stop receiving updates on the specified callback. If an update has
28524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * already been posted you may still receive it after calling this method.
28624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     *
28724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * @param callback The callback to remove
28824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     */
28916ac83bebda2a19930b9d692789f3b507c49951bRoboErik    public void unregisterCallback(Callback callback) {
29024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        if (callback == null) {
29124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            throw new IllegalArgumentException("callback cannot be null");
29224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
29316ac83bebda2a19930b9d692789f3b507c49951bRoboErik        mImpl.unregisterCallback(callback);
29424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    }
29524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
29624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    /**
29724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * Sends a generic command to the session. It is up to the session creator
29824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * to decide what commands and parameters they will support. As such,
29924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * commands should only be sent to sessions that the controller owns.
30024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     *
30124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * @param command The command to send
30224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * @param params Any parameters to include with the command
30324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * @param cb The callback to receive the result on
30424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     */
305b530c89bba371d2d575f10480b2e90914b0d3f3fGabriel Peal    public void sendCommand(String command, Bundle params, ResultReceiver cb) {
30624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        if (TextUtils.isEmpty(command)) {
30724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            throw new IllegalArgumentException("command cannot be null or empty");
30824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
309b530c89bba371d2d575f10480b2e90914b0d3f3fGabriel Peal        mImpl.sendCommand(command, params, cb);
31024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    }
31124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
31224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    /**
313aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik     * Get the session owner's package name.
314aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik     *
315aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik     * @return The package name of of the session owner.
316aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik     */
317aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik    public String getPackageName() {
318aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        return mImpl.getPackageName();
319aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik    }
320aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik
321aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik    /**
322aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik     * Gets the underlying framework
323aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik     * {@link android.media.session.MediaController} object.
32424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * <p>
32524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * This method is only supported on API 21+.
32624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * </p>
32724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     *
328aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik     * @return The underlying {@link android.media.session.MediaController}
329aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik     *         object, or null if none.
33024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     */
33124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    public Object getMediaController() {
33224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        return mImpl.getMediaController();
33324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    }
33424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
33524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    /**
33624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * Callback for receiving updates on from the session. A Callback can be
33716ac83bebda2a19930b9d692789f3b507c49951bRoboErik     * registered using {@link #registerCallback}
33824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     */
339e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik    public static abstract class Callback implements IBinder.DeathRecipient {
340e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        private final Object mCallbackObj;
341e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        private MessageHandler mHandler;
342e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
343e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        private boolean mRegistered = false;
34424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
34524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public Callback() {
34624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            if (android.os.Build.VERSION.SDK_INT >= 21) {
34724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown                mCallbackObj = MediaControllerCompatApi21.createCallback(new StubApi21());
34824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            } else {
349e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                mCallbackObj = new StubCompat();
35024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            }
35124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
35224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
35324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        /**
35423138c4b9be07abdab0cfdde2c62186359c9e7faRoboErik         * Override to handle the session being destroyed. The session is no
35523138c4b9be07abdab0cfdde2c62186359c9e7faRoboErik         * longer valid after this call and calls to it will be ignored.
35623138c4b9be07abdab0cfdde2c62186359c9e7faRoboErik         */
35723138c4b9be07abdab0cfdde2c62186359c9e7faRoboErik        public void onSessionDestroyed() {
35823138c4b9be07abdab0cfdde2c62186359c9e7faRoboErik        }
35923138c4b9be07abdab0cfdde2c62186359c9e7faRoboErik
36023138c4b9be07abdab0cfdde2c62186359c9e7faRoboErik        /**
36124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * Override to handle custom events sent by the session owner without a
36224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * specified interface. Controllers should only handle these for
36324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * sessions they own.
36424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         *
36524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * @param event The event from the session.
36624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * @param extras Optional parameters for the event.
36724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         */
36824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public void onSessionEvent(String event, Bundle extras) {
36924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
37024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
37124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        /**
37224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * Override to handle changes in playback state.
37324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         *
37424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * @param state The new playback state of the session
37524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         */
37624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public void onPlaybackStateChanged(PlaybackStateCompat state) {
37724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
37824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
37924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        /**
38024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * Override to handle changes to the current metadata.
38124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         *
38224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * @param metadata The current metadata for the session or null if none.
38324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * @see MediaMetadata
38424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         */
38524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public void onMetadataChanged(MediaMetadataCompat metadata) {
38624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
38724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
388aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        /**
389aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         * Override to handle changes to items in the queue.
390aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         *
391aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         * @see MediaSessionCompat.QueueItem
392aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         * @param queue A list of items in the current play queue. It should
393aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         *            include the currently playing item as well as previous and
394aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         *            upcoming items if applicable.
395aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         */
396aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        public void onQueueChanged(List<MediaSessionCompat.QueueItem> queue) {
397aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        }
398aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik
399aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        /**
400aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         * Override to handle changes to the queue title.
401aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         *
402aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         * @param title The title that should be displayed along with the play
403aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         *            queue such as "Now Playing". May be null if there is no
404aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         *            such title.
405aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         */
406aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        public void onQueueTitleChanged(CharSequence title) {
407aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        }
408aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik
409aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        /**
410aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         * Override to handle chagnes to the {@link MediaSessionCompat} extras.
411aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         *
412aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         * @param extras The extras that can include other information
413aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         *            associated with the {@link MediaSessionCompat}.
414aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         */
415aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        public void onExtrasChanged(Bundle extras) {
416aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        }
417aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik
418aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        /**
419aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         * Override to handle changes to the audio info.
420aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         *
421aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         * @param info The current audio info for this session.
422aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         */
423aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        public void onAudioInfoChanged(PlaybackInfo info) {
424aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        }
425aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik
426e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        @Override
427e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        public void binderDied() {
428e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            onSessionDestroyed();
429e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        }
430e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
431e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        /**
432e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik         * Set the handler to use for pre 21 callbacks.
433e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik         */
434e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        private void setHandler(Handler handler) {
435e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            mHandler = new MessageHandler(handler.getLooper());
436e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        }
437e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
43824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        private class StubApi21 implements MediaControllerCompatApi21.Callback {
43924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            @Override
44023138c4b9be07abdab0cfdde2c62186359c9e7faRoboErik            public void onSessionDestroyed() {
44123138c4b9be07abdab0cfdde2c62186359c9e7faRoboErik                Callback.this.onSessionDestroyed();
44223138c4b9be07abdab0cfdde2c62186359c9e7faRoboErik            }
44323138c4b9be07abdab0cfdde2c62186359c9e7faRoboErik
44423138c4b9be07abdab0cfdde2c62186359c9e7faRoboErik            @Override
44524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            public void onSessionEvent(String event, Bundle extras) {
44624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown                Callback.this.onSessionEvent(event, extras);
44724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            }
44824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
44924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            @Override
45024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            public void onPlaybackStateChanged(Object stateObj) {
45124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown                Callback.this.onPlaybackStateChanged(
45224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown                        PlaybackStateCompat.fromPlaybackState(stateObj));
45324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            }
45424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
45524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            @Override
45624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            public void onMetadataChanged(Object metadataObj) {
45724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown                Callback.this.onMetadataChanged(
45824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown                        MediaMetadataCompat.fromMediaMetadata(metadataObj));
45924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            }
46024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
461e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
462e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        private class StubCompat extends IMediaControllerCallback.Stub {
463e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
464e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            @Override
465e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            public void onEvent(String event, Bundle extras) throws RemoteException {
466e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                mHandler.post(MessageHandler.MSG_EVENT, event, extras);
467e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
468e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
469e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            @Override
470e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            public void onSessionDestroyed() throws RemoteException {
471e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                mHandler.post(MessageHandler.MSG_DESTROYED, null, null);
472e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
473e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
474e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            @Override
475e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            public void onPlaybackStateChanged(PlaybackStateCompat state) throws RemoteException {
476e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                mHandler.post(MessageHandler.MSG_UPDATE_PLAYBACK_STATE, state, null);
477e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
478e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
479e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            @Override
480e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            public void onMetadataChanged(MediaMetadataCompat metadata) throws RemoteException {
481e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                mHandler.post(MessageHandler.MSG_UPDATE_METADATA, metadata, null);
482e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
483e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
484e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            @Override
485e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            public void onQueueChanged(List<QueueItem> queue) throws RemoteException {
486e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                mHandler.post(MessageHandler.MSG_UPDATE_QUEUE, queue, null);
487e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
488e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
489e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            @Override
490e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            public void onQueueTitleChanged(CharSequence title) throws RemoteException {
491e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                mHandler.post(MessageHandler.MSG_UPDATE_QUEUE_TITLE, title, null);
492e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
493e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
494e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            @Override
495e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            public void onExtrasChanged(Bundle extras) throws RemoteException {
496e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                mHandler.post(MessageHandler.MSG_UPDATE_EXTRAS, extras, null);
497e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
498e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
499e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            @Override
500e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            public void onVolumeInfoChanged(ParcelableVolumeInfo info) throws RemoteException {
501e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                PlaybackInfo pi = null;
502e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                if (info != null) {
503e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                    pi = new PlaybackInfo(info.volumeType, info.audioStream, info.controlType,
504e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                            info.maxVolume, info.currentVolume);
505e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                }
506e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                mHandler.post(MessageHandler.MSG_UPDATE_VOLUME, pi, null);
507e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
508e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        }
509e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
510e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        private class MessageHandler extends Handler {
511e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            private static final int MSG_EVENT = 1;
512e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            private static final int MSG_UPDATE_PLAYBACK_STATE = 2;
513e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            private static final int MSG_UPDATE_METADATA = 3;
514e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            private static final int MSG_UPDATE_VOLUME = 4;
515e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            private static final int MSG_UPDATE_QUEUE = 5;
516e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            private static final int MSG_UPDATE_QUEUE_TITLE = 6;
517e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            private static final int MSG_UPDATE_EXTRAS = 7;
518e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            private static final int MSG_DESTROYED = 8;
519e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
520e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            public MessageHandler(Looper looper) {
521e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                super(looper);
522e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
523e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
524e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            @Override
525e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            public void handleMessage(Message msg) {
526e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                if (!mRegistered) {
527e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                    return;
528e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                }
529e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                switch (msg.what) {
530e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                    case MSG_EVENT:
531e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                        onSessionEvent((String) msg.obj, msg.getData());
532e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                        break;
533e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                    case MSG_UPDATE_PLAYBACK_STATE:
534e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                        onPlaybackStateChanged((PlaybackStateCompat) msg.obj);
535e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                        break;
536e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                    case MSG_UPDATE_METADATA:
537e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                        onMetadataChanged((MediaMetadataCompat) msg.obj);
538e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                        break;
539e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                    case MSG_UPDATE_QUEUE:
540e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                        onQueueChanged((List<MediaSessionCompat.QueueItem>) msg.obj);
541e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                        break;
542e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                    case MSG_UPDATE_QUEUE_TITLE:
543e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                        onQueueTitleChanged((CharSequence) msg.obj);
544e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                        break;
545e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                    case MSG_UPDATE_EXTRAS:
546e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                        onExtrasChanged((Bundle) msg.obj);
547e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                        break;
548e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                    case MSG_UPDATE_VOLUME:
549e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                        onAudioInfoChanged((PlaybackInfo) msg.obj);
550e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                        break;
551e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                    case MSG_DESTROYED:
552e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                        onSessionDestroyed();
553e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                        break;
554e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                }
555e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
556e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
557e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            public void post(int what, Object obj, Bundle data) {
558e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                obtainMessage(what, obj).sendToTarget();
559e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
560e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        }
56124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    }
56224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
56324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    /**
56424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * Interface for controlling media playback on a session. This allows an app
56524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * to send media transport commands to the session.
56624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     */
56724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    public static abstract class TransportControls {
56824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        TransportControls() {
56924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
57024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
57124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        /**
57224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * Request that the player start its playback at its current position.
57324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         */
57424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public abstract void play();
57524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
57624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        /**
577aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         * Request that the player start playback for a specific {@link Uri}.
578aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         *
579aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         * @param mediaId The uri of the requested media.
580aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         * @param extras Optional extras that can include extra information
581aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         *            about the media item to be played.
582aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         */
583aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        public abstract void playFromMediaId(String mediaId, Bundle extras);
584aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik
585aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        /**
586aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         * Request that the player start playback for a specific search query.
587aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         * An empty or null query should be treated as a request to play any
588aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         * music.
589aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         *
590aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         * @param query The search query.
591aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         * @param extras Optional extras that can include extra information
592aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         *            about the query.
593aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         */
594aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        public abstract void playFromSearch(String query, Bundle extras);
595aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik
596aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        /**
597b51f456b92aeb62d5aa9d67e1fb2725b2035fdddIan Lake         * Request that the player start playback for a specific {@link Uri}.
598b51f456b92aeb62d5aa9d67e1fb2725b2035fdddIan Lake         *
599b51f456b92aeb62d5aa9d67e1fb2725b2035fdddIan Lake         * @param uri  The URI of the requested media.
600b51f456b92aeb62d5aa9d67e1fb2725b2035fdddIan Lake         * @param extras Optional extras that can include extra information about the media item
601b51f456b92aeb62d5aa9d67e1fb2725b2035fdddIan Lake         *               to be played.
602b51f456b92aeb62d5aa9d67e1fb2725b2035fdddIan Lake         */
603b51f456b92aeb62d5aa9d67e1fb2725b2035fdddIan Lake        public abstract void playFromUri(Uri uri, Bundle extras);
604b51f456b92aeb62d5aa9d67e1fb2725b2035fdddIan Lake
605b51f456b92aeb62d5aa9d67e1fb2725b2035fdddIan Lake        /**
606aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         * Play an item with a specific id in the play queue. If you specify an
607aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         * id that is not in the play queue, the behavior is undefined.
608aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         */
609aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        public abstract void skipToQueueItem(long id);
610aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik
611aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        /**
61224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * Request that the player pause its playback and stay at its current
61324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * position.
61424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         */
61524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public abstract void pause();
61624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
61724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        /**
61824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * Request that the player stop its playback; it may clear its state in
61924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * whatever way is appropriate.
62024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         */
62124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public abstract void stop();
62224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
62324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        /**
62424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * Move to a new location in the media stream.
62524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         *
62624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * @param pos Position to move to, in milliseconds.
62724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         */
62824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public abstract void seekTo(long pos);
62924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
63024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        /**
63124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * Start fast forwarding. If playback is already fast forwarding this
63224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * may increase the rate.
63324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         */
63424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public abstract void fastForward();
63524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
63624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        /**
63724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * Skip to the next item.
63824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         */
63924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public abstract void skipToNext();
64024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
64124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        /**
64224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * Start rewinding. If playback is already rewinding this may increase
64324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * the rate.
64424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         */
64524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public abstract void rewind();
64624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
64724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        /**
64824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * Skip to the previous item.
64924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         */
65024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public abstract void skipToPrevious();
65124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
65224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        /**
65324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * Rate the current content. This will cause the rating to be set for
65424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * the current user. The Rating type must match the type returned by
65524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * {@link #getRatingType()}.
65624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         *
65724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * @param rating The rating to set for the current content
65824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         */
65924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public abstract void setRating(RatingCompat rating);
660aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik
661aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        /**
662aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         * Send a custom action for the {@link MediaSessionCompat} to perform.
663aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         *
664aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         * @param customAction The action to perform.
665aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         * @param args Optional arguments to supply to the
666aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         *            {@link MediaSessionCompat} for this custom action.
667aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         */
668aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        public abstract void sendCustomAction(PlaybackStateCompat.CustomAction customAction,
669aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik                Bundle args);
670aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik
671aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        /**
672aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         * Send the id and args from a custom action for the
673aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         * {@link MediaSessionCompat} to perform.
674aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         *
675aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         * @see #sendCustomAction(PlaybackStateCompat.CustomAction action,
676aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         *      Bundle args)
677aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         * @param action The action identifier of the
678aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         *            {@link PlaybackStateCompat.CustomAction} as specified by
679aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         *            the {@link MediaSessionCompat}.
680aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         * @param args Optional arguments to supply to the
681aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         *            {@link MediaSessionCompat} for this custom action.
682aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik         */
683aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        public abstract void sendCustomAction(String action, Bundle args);
68424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    }
68524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
68624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    /**
68724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * Holds information about the way volume is handled for this session.
68824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     */
689312f13dea7b4a9229dff784c6e94b0ec0c722b74RoboErik    public static final class PlaybackInfo {
690312f13dea7b4a9229dff784c6e94b0ec0c722b74RoboErik        /**
691312f13dea7b4a9229dff784c6e94b0ec0c722b74RoboErik         * The session uses local playback.
692312f13dea7b4a9229dff784c6e94b0ec0c722b74RoboErik         */
693312f13dea7b4a9229dff784c6e94b0ec0c722b74RoboErik        public static final int PLAYBACK_TYPE_LOCAL = 1;
694312f13dea7b4a9229dff784c6e94b0ec0c722b74RoboErik        /**
695312f13dea7b4a9229dff784c6e94b0ec0c722b74RoboErik         * The session uses remote playback.
696312f13dea7b4a9229dff784c6e94b0ec0c722b74RoboErik         */
697312f13dea7b4a9229dff784c6e94b0ec0c722b74RoboErik        public static final int PLAYBACK_TYPE_REMOTE = 2;
698312f13dea7b4a9229dff784c6e94b0ec0c722b74RoboErik
699312f13dea7b4a9229dff784c6e94b0ec0c722b74RoboErik        private final int mPlaybackType;
7001435afe32073dee10e721dfb6122ce6a194a6412RoboErik        // TODO update audio stream with AudioAttributes support version
70124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        private final int mAudioStream;
70224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        private final int mVolumeControl;
70324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        private final int mMaxVolume;
70424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        private final int mCurrentVolume;
70524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
706312f13dea7b4a9229dff784c6e94b0ec0c722b74RoboErik        PlaybackInfo(int type, int stream, int control, int max, int current) {
707312f13dea7b4a9229dff784c6e94b0ec0c722b74RoboErik            mPlaybackType = type;
70824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            mAudioStream = stream;
70924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            mVolumeControl = control;
71024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            mMaxVolume = max;
71124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            mCurrentVolume = current;
71224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
71324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
71424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        /**
71524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * Get the type of volume handling, either local or remote. One of:
71624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * <ul>
717312f13dea7b4a9229dff784c6e94b0ec0c722b74RoboErik         * <li>{@link PlaybackInfo#PLAYBACK_TYPE_LOCAL}</li>
718312f13dea7b4a9229dff784c6e94b0ec0c722b74RoboErik         * <li>{@link PlaybackInfo#PLAYBACK_TYPE_REMOTE}</li>
71924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * </ul>
72024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         *
72124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * @return The type of volume handling this session is using.
72224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         */
723312f13dea7b4a9229dff784c6e94b0ec0c722b74RoboErik        public int getPlaybackType() {
724312f13dea7b4a9229dff784c6e94b0ec0c722b74RoboErik            return mPlaybackType;
72524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
72624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
72724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        /**
72824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * Get the stream this is currently controlling volume on. When the volume
729312f13dea7b4a9229dff784c6e94b0ec0c722b74RoboErik         * type is {@link PlaybackInfo#PLAYBACK_TYPE_REMOTE} this value does not
73024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * have meaning and should be ignored.
73124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         *
73224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * @return The stream this session is playing on.
73324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         */
73424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public int getAudioStream() {
735aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik            // TODO switch to AudioAttributesCompat when it is added.
73624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            return mAudioStream;
73724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
73824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
73924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        /**
74024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * Get the type of volume control that can be used. One of:
74124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * <ul>
74224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * <li>{@link VolumeProviderCompat#VOLUME_CONTROL_ABSOLUTE}</li>
74324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * <li>{@link VolumeProviderCompat#VOLUME_CONTROL_RELATIVE}</li>
74424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * <li>{@link VolumeProviderCompat#VOLUME_CONTROL_FIXED}</li>
74524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * </ul>
74624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         *
74724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * @return The type of volume control that may be used with this
74824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         *         session.
74924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         */
75024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public int getVolumeControl() {
75124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            return mVolumeControl;
75224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
75324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
75424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        /**
75524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * Get the maximum volume that may be set for this session.
75624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         *
75724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * @return The maximum allowed volume where this session is playing.
75824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         */
75924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public int getMaxVolume() {
76024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            return mMaxVolume;
76124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
76224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
76324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        /**
76424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * Get the current volume for this session.
76524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         *
76624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * @return The current volume where this session is playing.
76724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         */
76824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public int getCurrentVolume() {
76924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            return mCurrentVolume;
77024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
77124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    }
77224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
77324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    interface MediaControllerImpl {
77416ac83bebda2a19930b9d692789f3b507c49951bRoboErik        void registerCallback(Callback callback, Handler handler);
77516ac83bebda2a19930b9d692789f3b507c49951bRoboErik
77616ac83bebda2a19930b9d692789f3b507c49951bRoboErik        void unregisterCallback(Callback callback);
77724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        boolean dispatchMediaButtonEvent(KeyEvent keyEvent);
77824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        TransportControls getTransportControls();
77924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        PlaybackStateCompat getPlaybackState();
78024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        MediaMetadataCompat getMetadata();
781aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik
782aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        List<MediaSessionCompat.QueueItem> getQueue();
783aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        CharSequence getQueueTitle();
784aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        Bundle getExtras();
78524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        int getRatingType();
786aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        long getFlags();
787312f13dea7b4a9229dff784c6e94b0ec0c722b74RoboErik        PlaybackInfo getPlaybackInfo();
788aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        PendingIntent getSessionActivity();
789aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik
790aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        void setVolumeTo(int value, int flags);
791aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        void adjustVolume(int direction, int flags);
792b530c89bba371d2d575f10480b2e90914b0d3f3fGabriel Peal        void sendCommand(String command, Bundle params, ResultReceiver cb);
793aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik
794aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        String getPackageName();
79524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        Object getMediaController();
79624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    }
79724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
79824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    static class MediaControllerImplBase implements MediaControllerImpl {
799e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        private MediaSessionCompat.Token mToken;
800e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        private IMediaSession mBinder;
801e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        private TransportControls mTransportControls;
802e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
803e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        public MediaControllerImplBase(MediaSessionCompat.Token token) {
804e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            mToken = token;
805e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            mBinder = IMediaSession.Stub.asInterface((IBinder) token.getToken());
806e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        }
807e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
80824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        @Override
80916ac83bebda2a19930b9d692789f3b507c49951bRoboErik        public void registerCallback(Callback callback, Handler handler) {
810e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            if (callback == null) {
811e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                throw new IllegalArgumentException("callback may not be null.");
812e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
813e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            try {
814e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                mBinder.asBinder().linkToDeath(callback, 0);
815e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                mBinder.registerCallbackListener((IMediaControllerCallback) callback.mCallbackObj);
816e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                callback.setHandler(handler);
817e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                callback.mRegistered = true;
818e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            } catch (RemoteException e) {
819e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                Log.e(TAG, "Dead object in registerCallback. " + e);
820e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                callback.onSessionDestroyed();
821e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
82224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
82324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
82424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        @Override
82516ac83bebda2a19930b9d692789f3b507c49951bRoboErik        public void unregisterCallback(Callback callback) {
826e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            if (callback == null) {
827e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                throw new IllegalArgumentException("callback may not be null.");
828e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
829e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            try {
830e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                mBinder.unregisterCallbackListener(
831e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                        (IMediaControllerCallback) callback.mCallbackObj);
832e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                mBinder.asBinder().unlinkToDeath(callback, 0);
833e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                callback.mRegistered = false;
834e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            } catch (RemoteException e) {
835e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                Log.e(TAG, "Dead object in unregisterCallback. " + e);
836e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
83724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
83824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
83924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        @Override
84024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public boolean dispatchMediaButtonEvent(KeyEvent event) {
841e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            if (event == null) {
842e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                throw new IllegalArgumentException("event may not be null.");
843e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
844e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            try {
845e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                mBinder.sendMediaButton(event);
846e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            } catch (RemoteException e) {
847e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                Log.e(TAG, "Dead object in dispatchMediaButtonEvent. " + e);
848e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
84924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            return false;
85024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
85124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
85224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        @Override
85324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public TransportControls getTransportControls() {
854e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            if (mTransportControls == null) {
855e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                mTransportControls = new TransportControlsBase(mBinder);
856e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
857e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
858e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            return mTransportControls;
85924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
86024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
86124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        @Override
86224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public PlaybackStateCompat getPlaybackState() {
863e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            try {
864e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                return mBinder.getPlaybackState();
865e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            } catch (RemoteException e) {
866e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                Log.e(TAG, "Dead object in getPlaybackState. " + e);
867e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
86824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            return null;
86924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
87024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
87124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        @Override
87224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public MediaMetadataCompat getMetadata() {
873e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            try {
874e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                return mBinder.getMetadata();
875e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            } catch (RemoteException e) {
876e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                Log.e(TAG, "Dead object in getMetadata. " + e);
877e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
87824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            return null;
87924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
88024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
88124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        @Override
882aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        public List<MediaSessionCompat.QueueItem> getQueue() {
883e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            try {
884e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                return mBinder.getQueue();
885e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            } catch (RemoteException e) {
886e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                Log.e(TAG, "Dead object in getQueue. " + e);
887e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
888aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik            return null;
889aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        }
890aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik
891aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        @Override
892aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        public CharSequence getQueueTitle() {
893e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            try {
894e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                return mBinder.getQueueTitle();
895e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            } catch (RemoteException e) {
896e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                Log.e(TAG, "Dead object in getQueueTitle. " + e);
897e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
898aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik            return null;
899aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        }
900aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik
901aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        @Override
902aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        public Bundle getExtras() {
903e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            try {
904e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                return mBinder.getExtras();
905e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            } catch (RemoteException e) {
906e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                Log.e(TAG, "Dead object in getExtras. " + e);
907e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
908aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik            return null;
909aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        }
910aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik
911aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        @Override
91224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public int getRatingType() {
913e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            try {
914e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                return mBinder.getRatingType();
915e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            } catch (RemoteException e) {
916e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                Log.e(TAG, "Dead object in getRatingType. " + e);
917e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
91824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            return 0;
91924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
92024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
92124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        @Override
922aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        public long getFlags() {
923e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            try {
924e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                return mBinder.getFlags();
925e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            } catch (RemoteException e) {
926e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                Log.e(TAG, "Dead object in getFlags. " + e);
927e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
928aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik            return 0;
929aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        }
930aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik
931aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        @Override
932312f13dea7b4a9229dff784c6e94b0ec0c722b74RoboErik        public PlaybackInfo getPlaybackInfo() {
933e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            try {
934e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                ParcelableVolumeInfo info = mBinder.getVolumeAttributes();
935e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                PlaybackInfo pi = new PlaybackInfo(info.volumeType, info.audioStream,
936e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                        info.controlType, info.maxVolume, info.currentVolume);
937e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                return pi;
938e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            } catch (RemoteException e) {
939e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                Log.e(TAG, "Dead object in getPlaybackInfo. " + e);
940e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
94124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            return null;
94224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
94324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
94424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        @Override
945aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        public PendingIntent getSessionActivity() {
946e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            try {
947e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                return mBinder.getLaunchPendingIntent();
948e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            } catch (RemoteException e) {
949e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                Log.e(TAG, "Dead object in getSessionActivity. " + e);
950e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
951aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik            return null;
952aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        }
953aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik
954aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        @Override
955aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        public void setVolumeTo(int value, int flags) {
956e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            try {
957e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                mBinder.setVolumeTo(value, flags, null);
958e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            } catch (RemoteException e) {
959e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                Log.e(TAG, "Dead object in setVolumeTo. " + e);
960e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
961aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        }
962aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik
963aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        @Override
964aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        public void adjustVolume(int direction, int flags) {
965e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            try {
966e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                mBinder.adjustVolume(direction, flags, null);
967e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            } catch (RemoteException e) {
968e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                Log.e(TAG, "Dead object in adjustVolume. " + e);
969e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
970aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        }
971aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik
972aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        @Override
973b530c89bba371d2d575f10480b2e90914b0d3f3fGabriel Peal        public void sendCommand(String command, Bundle params, ResultReceiver cb) {
974e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            try {
975e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                mBinder.sendCommand(command, params,
976e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                        new MediaSessionCompat.ResultReceiverWrapper(cb));
977e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            } catch (RemoteException e) {
978e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                Log.e(TAG, "Dead object in sendCommand. " + e);
979e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
98024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
98124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
98224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        @Override
983aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        public String getPackageName() {
984e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            try {
985e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                return mBinder.getPackageName();
986e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            } catch (RemoteException e) {
987e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                Log.e(TAG, "Dead object in getPackageName. " + e);
988e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
989aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik            return null;
990aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        }
991aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik
992aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        @Override
99324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public Object getMediaController() {
99424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            return null;
99524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
99624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    }
99724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
998e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik    static class TransportControlsBase extends TransportControls {
999e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        private IMediaSession mBinder;
1000e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
1001e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        public TransportControlsBase(IMediaSession binder) {
1002e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            mBinder = binder;
1003e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        }
1004e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
1005e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        @Override
1006e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        public void play() {
1007e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            try {
1008e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                mBinder.play();
1009e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            } catch (RemoteException e) {
1010e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                Log.e(TAG, "Dead object in play. " + e);
1011e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
1012e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        }
1013e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
1014e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        @Override
1015e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        public void playFromMediaId(String mediaId, Bundle extras) {
1016e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            try {
1017e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                mBinder.playFromMediaId(mediaId, extras);
1018e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            } catch (RemoteException e) {
1019e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                Log.e(TAG, "Dead object in playFromMediaId. " + e);
1020e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
1021e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        }
1022e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
1023e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        @Override
1024e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        public void playFromSearch(String query, Bundle extras) {
1025e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            try {
1026e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                mBinder.playFromSearch(query, extras);
1027e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            } catch (RemoteException e) {
1028e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                Log.e(TAG, "Dead object in playFromSearch. " + e);
1029e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
1030e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        }
1031e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
1032e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        @Override
1033b51f456b92aeb62d5aa9d67e1fb2725b2035fdddIan Lake        public void playFromUri(Uri uri, Bundle extras) {
1034b51f456b92aeb62d5aa9d67e1fb2725b2035fdddIan Lake            try {
1035b51f456b92aeb62d5aa9d67e1fb2725b2035fdddIan Lake                mBinder.playFromUri(uri, extras);
1036b51f456b92aeb62d5aa9d67e1fb2725b2035fdddIan Lake            } catch (RemoteException e) {
1037b51f456b92aeb62d5aa9d67e1fb2725b2035fdddIan Lake                Log.e(TAG, "Dead object in playFromUri. " + e);
1038b51f456b92aeb62d5aa9d67e1fb2725b2035fdddIan Lake            }
1039b51f456b92aeb62d5aa9d67e1fb2725b2035fdddIan Lake        }
1040b51f456b92aeb62d5aa9d67e1fb2725b2035fdddIan Lake
1041b51f456b92aeb62d5aa9d67e1fb2725b2035fdddIan Lake        @Override
1042e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        public void skipToQueueItem(long id) {
1043e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            try {
1044e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                mBinder.skipToQueueItem(id);
1045e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            } catch (RemoteException e) {
1046e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                Log.e(TAG, "Dead object in skipToQueueItem. " + e);
1047e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
1048e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        }
1049e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
1050e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        @Override
1051e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        public void pause() {
1052e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            try {
1053e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                mBinder.pause();
1054e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            } catch (RemoteException e) {
1055e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                Log.e(TAG, "Dead object in pause. " + e);
1056e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
1057e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        }
1058e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
1059e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        @Override
1060e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        public void stop() {
1061e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            try {
1062e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                mBinder.stop();
1063e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            } catch (RemoteException e) {
1064e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                Log.e(TAG, "Dead object in stop. " + e);
1065e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
1066e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        }
1067e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
1068e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        @Override
1069e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        public void seekTo(long pos) {
1070e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            try {
1071e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                mBinder.seekTo(pos);
1072e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            } catch (RemoteException e) {
1073e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                Log.e(TAG, "Dead object in seekTo. " + e);
1074e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
1075e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        }
1076e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
1077e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        @Override
1078e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        public void fastForward() {
1079e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            try {
1080e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                mBinder.fastForward();
1081e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            } catch (RemoteException e) {
1082e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                Log.e(TAG, "Dead object in fastForward. " + e);
1083e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
1084e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        }
1085e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
1086e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        @Override
1087e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        public void skipToNext() {
1088e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            try {
1089e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                mBinder.next();
1090e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            } catch (RemoteException e) {
1091e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                Log.e(TAG, "Dead object in skipToNext. " + e);
1092e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
1093e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        }
1094e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
1095e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        @Override
1096e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        public void rewind() {
1097e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            try {
1098e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                mBinder.rewind();
1099e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            } catch (RemoteException e) {
1100e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                Log.e(TAG, "Dead object in rewind. " + e);
1101e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
1102e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        }
1103e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
1104e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        @Override
1105e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        public void skipToPrevious() {
1106e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            try {
1107e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                mBinder.previous();
1108e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            } catch (RemoteException e) {
1109e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                Log.e(TAG, "Dead object in skipToPrevious. " + e);
1110e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
1111e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        }
1112e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
1113e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        @Override
1114e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        public void setRating(RatingCompat rating) {
1115e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            try {
1116e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                mBinder.rate(rating);
1117e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            } catch (RemoteException e) {
1118e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                Log.e(TAG, "Dead object in setRating. " + e);
1119e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
1120e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        }
1121e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
1122e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        @Override
1123e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        public void sendCustomAction(CustomAction customAction, Bundle args) {
1124e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            sendCustomAction(customAction.getAction(), args);
1125e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        }
1126e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
1127e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        @Override
1128e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        public void sendCustomAction(String action, Bundle args) {
1129e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            try {
1130e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                mBinder.sendCustomAction(action, args);
1131e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            } catch (RemoteException e) {
1132e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik                Log.e(TAG, "Dead object in sendCustomAction. " + e);
1133e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik            }
1134e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik        }
1135e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik    }
1136e49860b0f76d8336c1d41831ed370b0ff94278efRoboErik
113724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    static class MediaControllerImplApi21 implements MediaControllerImpl {
1138b51f456b92aeb62d5aa9d67e1fb2725b2035fdddIan Lake        protected final Object mControllerObj;
113924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
114024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public MediaControllerImplApi21(Context context, MediaSessionCompat session) {
11415c41750574ba65da432b69f89cd32dc356281005RoboErik            mControllerObj = MediaControllerCompatApi21.fromToken(context,
114224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown                    session.getSessionToken().getToken());
114324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
114424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
114524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public MediaControllerImplApi21(Context context, MediaSessionCompat.Token sessionToken)
114624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown                throws RemoteException {
11475c41750574ba65da432b69f89cd32dc356281005RoboErik            mControllerObj = MediaControllerCompatApi21.fromToken(context,
114824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown                    sessionToken.getToken());
114924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            if (mControllerObj == null) throw new RemoteException();
115024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
115124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
115224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        @Override
115316ac83bebda2a19930b9d692789f3b507c49951bRoboErik        public void registerCallback(Callback callback, Handler handler) {
115416ac83bebda2a19930b9d692789f3b507c49951bRoboErik            MediaControllerCompatApi21.registerCallback(mControllerObj, callback.mCallbackObj, handler);
115524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
115624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
115724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        @Override
115816ac83bebda2a19930b9d692789f3b507c49951bRoboErik        public void unregisterCallback(Callback callback) {
115916ac83bebda2a19930b9d692789f3b507c49951bRoboErik            MediaControllerCompatApi21.unregisterCallback(mControllerObj, callback.mCallbackObj);
116024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
116124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
116224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        @Override
116324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public boolean dispatchMediaButtonEvent(KeyEvent event) {
116424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            return MediaControllerCompatApi21.dispatchMediaButtonEvent(mControllerObj, event);
116524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
116624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
116724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        @Override
116824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public TransportControls getTransportControls() {
11691435afe32073dee10e721dfb6122ce6a194a6412RoboErik            Object controlsObj = MediaControllerCompatApi21.getTransportControls(mControllerObj);
117024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            return controlsObj != null ? new TransportControlsApi21(controlsObj) : null;
117124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
117224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
117324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        @Override
117424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public PlaybackStateCompat getPlaybackState() {
117524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            Object stateObj = MediaControllerCompatApi21.getPlaybackState(mControllerObj);
117624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            return stateObj != null ? PlaybackStateCompat.fromPlaybackState(stateObj) : null;
117724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
117824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
117924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        @Override
118024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public MediaMetadataCompat getMetadata() {
118124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            Object metadataObj = MediaControllerCompatApi21.getMetadata(mControllerObj);
118224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            return metadataObj != null ? MediaMetadataCompat.fromMediaMetadata(metadataObj) : null;
118324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
118424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
118524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        @Override
1186aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        public List<MediaSessionCompat.QueueItem> getQueue() {
1187aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik            List<Object> queueObjs = MediaControllerCompatApi21.getQueue(mControllerObj);
1188aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik            if (queueObjs == null) {
1189aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik                return null;
1190aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik            }
1191aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik            List<MediaSessionCompat.QueueItem> queue =
1192aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik                    new ArrayList<MediaSessionCompat.QueueItem>();
1193aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik            for (Object item : queueObjs) {
1194aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik                queue.add(MediaSessionCompat.QueueItem.obtain(item));
1195aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik            }
1196aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik            return queue;
1197aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        }
1198aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik
1199aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        @Override
1200aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        public CharSequence getQueueTitle() {
1201aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik            return MediaControllerCompatApi21.getQueueTitle(mControllerObj);
1202aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        }
1203aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik
1204aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        @Override
1205aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        public Bundle getExtras() {
1206aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik            return MediaControllerCompatApi21.getExtras(mControllerObj);
1207aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        }
1208aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik
1209aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        @Override
121024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public int getRatingType() {
121124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            return MediaControllerCompatApi21.getRatingType(mControllerObj);
121224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
121324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
121424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        @Override
1215aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        public long getFlags() {
1216aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik            return MediaControllerCompatApi21.getFlags(mControllerObj);
1217aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        }
1218aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik
1219aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        @Override
1220312f13dea7b4a9229dff784c6e94b0ec0c722b74RoboErik        public PlaybackInfo getPlaybackInfo() {
1221312f13dea7b4a9229dff784c6e94b0ec0c722b74RoboErik            Object volumeInfoObj = MediaControllerCompatApi21.getPlaybackInfo(mControllerObj);
1222312f13dea7b4a9229dff784c6e94b0ec0c722b74RoboErik            return volumeInfoObj != null ? new PlaybackInfo(
1223312f13dea7b4a9229dff784c6e94b0ec0c722b74RoboErik                    MediaControllerCompatApi21.PlaybackInfo.getPlaybackType(volumeInfoObj),
1224312f13dea7b4a9229dff784c6e94b0ec0c722b74RoboErik                    MediaControllerCompatApi21.PlaybackInfo.getLegacyAudioStream(volumeInfoObj),
1225312f13dea7b4a9229dff784c6e94b0ec0c722b74RoboErik                    MediaControllerCompatApi21.PlaybackInfo.getVolumeControl(volumeInfoObj),
1226312f13dea7b4a9229dff784c6e94b0ec0c722b74RoboErik                    MediaControllerCompatApi21.PlaybackInfo.getMaxVolume(volumeInfoObj),
1227312f13dea7b4a9229dff784c6e94b0ec0c722b74RoboErik                    MediaControllerCompatApi21.PlaybackInfo.getCurrentVolume(volumeInfoObj)) : null;
122824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
122924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
123024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        @Override
1231aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        public PendingIntent getSessionActivity() {
1232aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik            return MediaControllerCompatApi21.getSessionActivity(mControllerObj);
1233aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        }
1234aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik
1235aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        @Override
1236aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        public void setVolumeTo(int value, int flags) {
1237aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik            MediaControllerCompatApi21.setVolumeTo(mControllerObj, value, flags);
1238aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        }
1239aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik
1240aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        @Override
1241aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        public void adjustVolume(int direction, int flags) {
1242aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik            MediaControllerCompatApi21.adjustVolume(mControllerObj, direction, flags);
1243aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        }
1244aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik
1245aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        @Override
1246b530c89bba371d2d575f10480b2e90914b0d3f3fGabriel Peal        public void sendCommand(String command, Bundle params, ResultReceiver cb) {
1247b530c89bba371d2d575f10480b2e90914b0d3f3fGabriel Peal            MediaControllerCompatApi21.sendCommand(mControllerObj, command, params, cb);
124824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
124924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
125024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        @Override
1251aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        public String getPackageName() {
1252aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik            return MediaControllerCompatApi21.getPackageName(mControllerObj);
1253aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        }
1254aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik
1255aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        @Override
125624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public Object getMediaController() {
125724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            return mControllerObj;
125824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
125924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    }
126024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
126124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    static class TransportControlsApi21 extends TransportControls {
1262b51f456b92aeb62d5aa9d67e1fb2725b2035fdddIan Lake        protected final Object mControlsObj;
126324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
126424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public TransportControlsApi21(Object controlsObj) {
126524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            mControlsObj = controlsObj;
126624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
126724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
126824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        @Override
126924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public void play() {
127024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            MediaControllerCompatApi21.TransportControls.play(mControlsObj);
127124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
127224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
127324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        @Override
127424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public void pause() {
127524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            MediaControllerCompatApi21.TransportControls.pause(mControlsObj);
127624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
127724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
127824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        @Override
127924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public void stop() {
128024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            MediaControllerCompatApi21.TransportControls.stop(mControlsObj);
128124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
128224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
128324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        @Override
128424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public void seekTo(long pos) {
128524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            MediaControllerCompatApi21.TransportControls.seekTo(mControlsObj, pos);
128624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
128724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
128824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        @Override
128924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public void fastForward() {
129024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            MediaControllerCompatApi21.TransportControls.fastForward(mControlsObj);
129124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
129224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
129324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        @Override
129424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public void rewind() {
129524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            MediaControllerCompatApi21.TransportControls.rewind(mControlsObj);
129624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
129724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
129824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        @Override
129924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public void skipToNext() {
130024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            MediaControllerCompatApi21.TransportControls.skipToNext(mControlsObj);
130124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
130224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
130324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        @Override
130424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public void skipToPrevious() {
130524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            MediaControllerCompatApi21.TransportControls.skipToPrevious(mControlsObj);
130624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
130724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
130824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        @Override
130924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public void setRating(RatingCompat rating) {
131024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            MediaControllerCompatApi21.TransportControls.setRating(mControlsObj,
131124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown                    rating != null ? rating.getRating() : null);
131224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
1313aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik
1314aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        @Override
1315aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        public void playFromMediaId(String mediaId, Bundle extras) {
1316aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik            MediaControllerCompatApi21.TransportControls.playFromMediaId(mControlsObj, mediaId,
1317aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik                    extras);
1318aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        }
1319aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik
1320aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        @Override
1321aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        public void playFromSearch(String query, Bundle extras) {
1322aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik            MediaControllerCompatApi21.TransportControls.playFromSearch(mControlsObj, query,
1323aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik                    extras);
1324aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        }
1325aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik
1326aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        @Override
1327b51f456b92aeb62d5aa9d67e1fb2725b2035fdddIan Lake        public void playFromUri(Uri uri, Bundle extras) {
1328b51f456b92aeb62d5aa9d67e1fb2725b2035fdddIan Lake        }
1329b51f456b92aeb62d5aa9d67e1fb2725b2035fdddIan Lake
1330b51f456b92aeb62d5aa9d67e1fb2725b2035fdddIan Lake        @Override
1331aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        public void skipToQueueItem(long id) {
1332aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik            MediaControllerCompatApi21.TransportControls.skipToQueueItem(mControlsObj, id);
1333aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        }
1334aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik
1335aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        @Override
1336aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        public void sendCustomAction(CustomAction customAction, Bundle args) {
1337aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik            MediaControllerCompatApi21.TransportControls.sendCustomAction(mControlsObj,
1338aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik                    customAction.getAction(), args);
1339aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        }
1340aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik
1341aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        @Override
1342aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        public void sendCustomAction(String action, Bundle args) {
1343aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik            MediaControllerCompatApi21.TransportControls.sendCustomAction(mControlsObj, action,
1344aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik                    args);
1345aeb95a772d4365008145407ed52dfbaa61d3c4acRoboErik        }
134624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    }
1347b51f456b92aeb62d5aa9d67e1fb2725b2035fdddIan Lake
1348b51f456b92aeb62d5aa9d67e1fb2725b2035fdddIan Lake    static class MediaControllerImplApi23 extends MediaControllerImplApi21 {
1349b51f456b92aeb62d5aa9d67e1fb2725b2035fdddIan Lake
1350b51f456b92aeb62d5aa9d67e1fb2725b2035fdddIan Lake        public MediaControllerImplApi23(Context context, MediaSessionCompat session) {
1351b51f456b92aeb62d5aa9d67e1fb2725b2035fdddIan Lake            super(context, session);
1352b51f456b92aeb62d5aa9d67e1fb2725b2035fdddIan Lake        }
1353b51f456b92aeb62d5aa9d67e1fb2725b2035fdddIan Lake
1354b51f456b92aeb62d5aa9d67e1fb2725b2035fdddIan Lake        public MediaControllerImplApi23(Context context, MediaSessionCompat.Token sessionToken)
1355b51f456b92aeb62d5aa9d67e1fb2725b2035fdddIan Lake                throws RemoteException {
1356b51f456b92aeb62d5aa9d67e1fb2725b2035fdddIan Lake            super(context, sessionToken);
1357b51f456b92aeb62d5aa9d67e1fb2725b2035fdddIan Lake        }
1358b51f456b92aeb62d5aa9d67e1fb2725b2035fdddIan Lake
1359b51f456b92aeb62d5aa9d67e1fb2725b2035fdddIan Lake        @Override
1360b51f456b92aeb62d5aa9d67e1fb2725b2035fdddIan Lake        public TransportControls getTransportControls() {
1361b51f456b92aeb62d5aa9d67e1fb2725b2035fdddIan Lake            Object controlsObj = MediaControllerCompatApi21.getTransportControls(mControllerObj);
1362b51f456b92aeb62d5aa9d67e1fb2725b2035fdddIan Lake            return controlsObj != null ? new TransportControlsApi23(controlsObj) : null;
1363b51f456b92aeb62d5aa9d67e1fb2725b2035fdddIan Lake        }
1364b51f456b92aeb62d5aa9d67e1fb2725b2035fdddIan Lake    }
1365b51f456b92aeb62d5aa9d67e1fb2725b2035fdddIan Lake
1366b51f456b92aeb62d5aa9d67e1fb2725b2035fdddIan Lake    static class TransportControlsApi23 extends TransportControlsApi21 {
1367b51f456b92aeb62d5aa9d67e1fb2725b2035fdddIan Lake
1368b51f456b92aeb62d5aa9d67e1fb2725b2035fdddIan Lake        public TransportControlsApi23(Object controlsObj) {
1369b51f456b92aeb62d5aa9d67e1fb2725b2035fdddIan Lake            super(controlsObj);
1370b51f456b92aeb62d5aa9d67e1fb2725b2035fdddIan Lake        }
1371b51f456b92aeb62d5aa9d67e1fb2725b2035fdddIan Lake
1372b51f456b92aeb62d5aa9d67e1fb2725b2035fdddIan Lake        @Override
1373b51f456b92aeb62d5aa9d67e1fb2725b2035fdddIan Lake        public void playFromUri(Uri uri, Bundle extras) {
1374b51f456b92aeb62d5aa9d67e1fb2725b2035fdddIan Lake            MediaControllerCompatApi23.TransportControls.playFromUri(mControlsObj, uri,
1375b51f456b92aeb62d5aa9d67e1fb2725b2035fdddIan Lake                    extras);
1376b51f456b92aeb62d5aa9d67e1fb2725b2035fdddIan Lake        }
1377b51f456b92aeb62d5aa9d67e1fb2725b2035fdddIan Lake    }
137824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown}
1379