MediaControllerCompat.java revision 5c41750574ba65da432b69f89cd32dc356281005
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
1924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brownimport android.content.Context;
2024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brownimport android.os.Bundle;
2124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brownimport android.os.Handler;
2224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brownimport android.os.RemoteException;
2324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brownimport android.os.ResultReceiver;
2424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brownimport android.support.v4.media.MediaMetadataCompat;
2524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brownimport android.support.v4.media.RatingCompat;
2624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brownimport android.support.v4.media.VolumeProviderCompat;
2724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brownimport android.text.TextUtils;
2824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brownimport android.view.KeyEvent;
2924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
3024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown/**
3124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown * Allows an app to interact with an ongoing media session. Media buttons and
3224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown * other commands can be sent to the session. A callback may be registered to
3324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown * receive updates from the session, such as metadata and play state changes.
3424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown * <p>
3524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown * A MediaController can be created if you have a {@link MediaSessionCompat.Token}
3624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown * from the session owner.
3724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown * <p>
3824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown * MediaController objects are thread-safe.
3924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown * <p>
4024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown * This is a helper for accessing features in {@link android.media.session.MediaSession}
4124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown * introduced after API level 4 in a backwards compatible fashion.
4224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown */
4324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brownpublic final class MediaControllerCompat {
4424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    private final MediaControllerImpl mImpl;
4524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
4624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    /**
4724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * Creates a media controller from a session.
4824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     *
4924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * @param session The session to be controlled.
5024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     */
5124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    public MediaControllerCompat(Context context, MediaSessionCompat session) {
5224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        if (session == null) {
5324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            throw new IllegalArgumentException("session must not be null");
5424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
5524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
5624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        if (android.os.Build.VERSION.SDK_INT >= 21) {
5724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            mImpl = new MediaControllerImplApi21(context, session);
5824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        } else {
5924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            mImpl = new MediaControllerImplBase();
6024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
6124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    }
6224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
6324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    /**
6424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * Creates a media controller from a session token which may have
6524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * been obtained from another process.
6624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     *
6724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * @param sessionToken The token of the session to be controlled.
6824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * @throws RemoteException if the session is not accessible.
6924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     */
7024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    public MediaControllerCompat(Context context, MediaSessionCompat.Token sessionToken)
7124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            throws RemoteException {
7224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        if (sessionToken == null) {
7324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            throw new IllegalArgumentException("sessionToken must not be null");
7424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
7524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
7624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        if (android.os.Build.VERSION.SDK_INT >= 21) {
7724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            mImpl = new MediaControllerImplApi21(context, sessionToken);
7824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        } else {
7924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            mImpl = new MediaControllerImplBase();
8024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
8124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    }
8224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
8324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    /**
8424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * Get a {@link TransportControls} instance for this session.
8524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     *
8624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * @return A controls instance
8724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     */
8824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    public TransportControls getTransportControls() {
8924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        return mImpl.getTransportControls();
9024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    }
9124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
9224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    /**
9324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * Send the specified media button event to the session. Only media keys can
9424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * be sent by this method, other keys will be ignored.
9524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     *
9624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * @param keyEvent The media button event to dispatch.
9724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * @return true if the event was sent to the session, false otherwise.
9824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     */
9924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    public boolean dispatchMediaButtonEvent(KeyEvent keyEvent) {
10024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        if (keyEvent == null) {
10124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            throw new IllegalArgumentException("KeyEvent may not be null");
10224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
10324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        return mImpl.dispatchMediaButtonEvent(keyEvent);
10424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    }
10524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
10624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    /**
10724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * Get the current playback state for this session.
10824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     *
10924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * @return The current PlaybackState or null
11024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     */
11124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    public PlaybackStateCompat getPlaybackState() {
11224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        return mImpl.getPlaybackState();
11324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    }
11424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
11524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    /**
11624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * Get the current metadata for this session.
11724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     *
11824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * @return The current MediaMetadata or null.
11924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     */
12024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    public MediaMetadataCompat getMetadata() {
12124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        return mImpl.getMetadata();
12224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    }
12324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
12424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    /**
12524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * Get the rating type supported by the session. One of:
12624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * <ul>
12724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * <li>{@link RatingCompat#RATING_NONE}</li>
12824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * <li>{@link RatingCompat#RATING_HEART}</li>
12924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * <li>{@link RatingCompat#RATING_THUMB_UP_DOWN}</li>
13024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * <li>{@link RatingCompat#RATING_3_STARS}</li>
13124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * <li>{@link RatingCompat#RATING_4_STARS}</li>
13224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * <li>{@link RatingCompat#RATING_5_STARS}</li>
13324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * <li>{@link RatingCompat#RATING_PERCENTAGE}</li>
13424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * </ul>
13524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     *
13624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * @return The supported rating type
13724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     */
13824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    public int getRatingType() {
13924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        return mImpl.getRatingType();
14024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    }
14124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
14224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    /**
14324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * Get the current volume info for this session.
14424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     *
14524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * @return The current volume info or null.
14624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     */
14724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    public VolumeInfo getVolumeInfo() {
14824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        return mImpl.getVolumeInfo();
14924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    }
15024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
15124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    /**
15224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * Adds a callback to receive updates from the Session. Updates will be
15324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * posted on the caller's thread.
15424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     *
15524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * @param callback The callback object, must not be null.
15624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     */
15724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    public void addCallback(Callback callback) {
15824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        addCallback(callback, null);
15924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    }
16024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
16124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    /**
16224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * Adds a callback to receive updates from the session. Updates will be
16324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * posted on the specified handler's thread.
16424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     *
16524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * @param callback The callback object, must not be null.
16624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * @param handler The handler to post updates on. If null the callers thread
16724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     *            will be used.
16824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     */
16924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    public void addCallback(Callback callback, Handler handler) {
17024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        if (callback == null) {
17124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            throw new IllegalArgumentException("callback cannot be null");
17224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
17324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        if (handler == null) {
17424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            handler = new Handler();
17524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
17624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        mImpl.addCallback(callback, handler);
17724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    }
17824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
17924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    /**
18024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * Stop receiving updates on the specified callback. If an update has
18124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * already been posted you may still receive it after calling this method.
18224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     *
18324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * @param callback The callback to remove
18424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     */
18524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    public void removeCallback(Callback callback) {
18624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        if (callback == null) {
18724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            throw new IllegalArgumentException("callback cannot be null");
18824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
18924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        mImpl.removeCallback(callback);
19024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    }
19124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
19224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    /**
19324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * Sends a generic command to the session. It is up to the session creator
19424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * to decide what commands and parameters they will support. As such,
19524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * commands should only be sent to sessions that the controller owns.
19624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     *
19724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * @param command The command to send
19824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * @param params Any parameters to include with the command
19924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * @param cb The callback to receive the result on
20024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     */
201b530c89bba371d2d575f10480b2e90914b0d3f3fGabriel Peal    public void sendCommand(String command, Bundle params, ResultReceiver cb) {
20224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        if (TextUtils.isEmpty(command)) {
20324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            throw new IllegalArgumentException("command cannot be null or empty");
20424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
205b530c89bba371d2d575f10480b2e90914b0d3f3fGabriel Peal        mImpl.sendCommand(command, params, cb);
20624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    }
20724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
20824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    /**
20924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * Gets the underlying framework {@link android.media.session.MediaController} object.
21024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * <p>
21124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * This method is only supported on API 21+.
21224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * </p>
21324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     *
21424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * @return The underlying {@link android.media.session.MediaController} object,
21524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * or null if none.
21624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     */
21724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    public Object getMediaController() {
21824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        return mImpl.getMediaController();
21924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    }
22024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
22124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    /**
22224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * Callback for receiving updates on from the session. A Callback can be
22324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * registered using {@link #addCallback}
22424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     */
22524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    public static abstract class Callback {
22624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        final Object mCallbackObj;
22724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
22824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public Callback() {
22924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            if (android.os.Build.VERSION.SDK_INT >= 21) {
23024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown                mCallbackObj = MediaControllerCompatApi21.createCallback(new StubApi21());
23124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            } else {
23224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown                mCallbackObj = null;
23324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            }
23424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
23524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
23624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        /**
23724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * Override to handle custom events sent by the session owner without a
23824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * specified interface. Controllers should only handle these for
23924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * sessions they own.
24024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         *
24124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * @param event The event from the session.
24224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * @param extras Optional parameters for the event.
24324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         */
24424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public void onSessionEvent(String event, Bundle extras) {
24524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
24624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
24724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        /**
24824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * Override to handle changes in playback state.
24924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         *
25024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * @param state The new playback state of the session
25124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         */
25224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public void onPlaybackStateChanged(PlaybackStateCompat state) {
25324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
25424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
25524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        /**
25624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * Override to handle changes to the current metadata.
25724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         *
25824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * @param metadata The current metadata for the session or null if none.
25924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * @see MediaMetadata
26024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         */
26124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public void onMetadataChanged(MediaMetadataCompat metadata) {
26224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
26324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
26424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        private class StubApi21 implements MediaControllerCompatApi21.Callback {
26524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            @Override
26624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            public void onSessionEvent(String event, Bundle extras) {
26724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown                Callback.this.onSessionEvent(event, extras);
26824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            }
26924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
27024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            @Override
27124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            public void onPlaybackStateChanged(Object stateObj) {
27224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown                Callback.this.onPlaybackStateChanged(
27324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown                        PlaybackStateCompat.fromPlaybackState(stateObj));
27424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            }
27524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
27624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            @Override
27724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            public void onMetadataChanged(Object metadataObj) {
27824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown                Callback.this.onMetadataChanged(
27924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown                        MediaMetadataCompat.fromMediaMetadata(metadataObj));
28024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            }
28124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
28224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    }
28324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
28424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    /**
28524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * Interface for controlling media playback on a session. This allows an app
28624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * to send media transport commands to the session.
28724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     */
28824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    public static abstract class TransportControls {
28924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        TransportControls() {
29024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
29124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
29224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        /**
29324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * Request that the player start its playback at its current position.
29424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         */
29524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public abstract void play();
29624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
29724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        /**
29824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * Request that the player pause its playback and stay at its current
29924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * position.
30024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         */
30124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public abstract void pause();
30224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
30324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        /**
30424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * Request that the player stop its playback; it may clear its state in
30524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * whatever way is appropriate.
30624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         */
30724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public abstract void stop();
30824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
30924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        /**
31024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * Move to a new location in the media stream.
31124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         *
31224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * @param pos Position to move to, in milliseconds.
31324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         */
31424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public abstract void seekTo(long pos);
31524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
31624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        /**
31724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * Start fast forwarding. If playback is already fast forwarding this
31824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * may increase the rate.
31924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         */
32024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public abstract void fastForward();
32124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
32224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        /**
32324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * Skip to the next item.
32424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         */
32524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public abstract void skipToNext();
32624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
32724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        /**
32824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * Start rewinding. If playback is already rewinding this may increase
32924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * the rate.
33024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         */
33124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public abstract void rewind();
33224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
33324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        /**
33424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * Skip to the previous item.
33524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         */
33624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public abstract void skipToPrevious();
33724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
33824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        /**
33924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * Rate the current content. This will cause the rating to be set for
34024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * the current user. The Rating type must match the type returned by
34124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * {@link #getRatingType()}.
34224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         *
34324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * @param rating The rating to set for the current content
34424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         */
34524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public abstract void setRating(RatingCompat rating);
34624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    }
34724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
34824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    /**
34924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     * Holds information about the way volume is handled for this session.
35024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown     */
35124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    public static final class VolumeInfo {
35224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        private final int mVolumeType;
3531435afe32073dee10e721dfb6122ce6a194a6412RoboErik        // TODO update audio stream with AudioAttributes support version
35424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        private final int mAudioStream;
35524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        private final int mVolumeControl;
35624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        private final int mMaxVolume;
35724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        private final int mCurrentVolume;
35824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
35924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        VolumeInfo(int type, int stream, int control, int max, int current) {
36024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            mVolumeType = type;
36124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            mAudioStream = stream;
36224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            mVolumeControl = control;
36324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            mMaxVolume = max;
36424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            mCurrentVolume = current;
36524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
36624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
36724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        /**
36824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * Get the type of volume handling, either local or remote. One of:
36924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * <ul>
37024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * <li>{@link MediaSessionCompat#VOLUME_TYPE_LOCAL}</li>
37124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * <li>{@link MediaSessionCompat#VOLUME_TYPE_REMOTE}</li>
37224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * </ul>
37324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         *
37424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * @return The type of volume handling this session is using.
37524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         */
37624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public int getVolumeType() {
37724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            return mVolumeType;
37824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
37924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
38024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        /**
38124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * Get the stream this is currently controlling volume on. When the volume
38224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * type is {@link MediaSessionCompat#VOLUME_TYPE_REMOTE} this value does not
38324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * have meaning and should be ignored.
38424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         *
38524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * @return The stream this session is playing on.
38624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         */
38724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public int getAudioStream() {
38824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            return mAudioStream;
38924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
39024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
39124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        /**
39224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * Get the type of volume control that can be used. One of:
39324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * <ul>
39424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * <li>{@link VolumeProviderCompat#VOLUME_CONTROL_ABSOLUTE}</li>
39524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * <li>{@link VolumeProviderCompat#VOLUME_CONTROL_RELATIVE}</li>
39624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * <li>{@link VolumeProviderCompat#VOLUME_CONTROL_FIXED}</li>
39724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * </ul>
39824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         *
39924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * @return The type of volume control that may be used with this
40024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         *         session.
40124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         */
40224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public int getVolumeControl() {
40324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            return mVolumeControl;
40424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
40524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
40624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        /**
40724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * Get the maximum volume that may be set for this session.
40824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         *
40924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * @return The maximum allowed volume where this session is playing.
41024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         */
41124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public int getMaxVolume() {
41224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            return mMaxVolume;
41324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
41424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
41524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        /**
41624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * Get the current volume for this session.
41724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         *
41824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         * @return The current volume where this session is playing.
41924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown         */
42024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public int getCurrentVolume() {
42124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            return mCurrentVolume;
42224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
42324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    }
42424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
42524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    interface MediaControllerImpl {
42624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        void addCallback(Callback callback, Handler handler);
42724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        void removeCallback(Callback callback);
42824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        boolean dispatchMediaButtonEvent(KeyEvent keyEvent);
42924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        TransportControls getTransportControls();
43024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        PlaybackStateCompat getPlaybackState();
43124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        MediaMetadataCompat getMetadata();
43224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        int getRatingType();
43324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        VolumeInfo getVolumeInfo();
434b530c89bba371d2d575f10480b2e90914b0d3f3fGabriel Peal        void sendCommand(String command, Bundle params, ResultReceiver cb);
43524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        Object getMediaController();
43624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    }
43724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
43824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    // TODO: compatibility implementation
43924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    static class MediaControllerImplBase implements MediaControllerImpl {
44024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        @Override
44124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public void addCallback(Callback callback, Handler handler) {
44224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
44324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
44424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        @Override
44524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public void removeCallback(Callback callback) {
44624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
44724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
44824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        @Override
44924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public boolean dispatchMediaButtonEvent(KeyEvent event) {
45024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            return false;
45124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
45224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
45324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        @Override
45424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public TransportControls getTransportControls() {
45524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            return null;
45624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
45724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
45824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        @Override
45924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public PlaybackStateCompat getPlaybackState() {
46024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            return null;
46124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
46224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
46324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        @Override
46424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public MediaMetadataCompat getMetadata() {
46524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            return null;
46624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
46724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
46824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        @Override
46924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public int getRatingType() {
47024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            return 0;
47124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
47224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
47324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        @Override
47424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public VolumeInfo getVolumeInfo() {
47524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            return null;
47624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
47724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
47824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        @Override
479b530c89bba371d2d575f10480b2e90914b0d3f3fGabriel Peal        public void sendCommand(String command, Bundle params, ResultReceiver cb) {
48024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
48124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
48224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        @Override
48324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public Object getMediaController() {
48424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            return null;
48524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
48624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    }
48724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
48824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    static class MediaControllerImplApi21 implements MediaControllerImpl {
48924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        private final Object mControllerObj;
49024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
49124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public MediaControllerImplApi21(Context context, MediaSessionCompat session) {
4925c41750574ba65da432b69f89cd32dc356281005RoboErik            mControllerObj = MediaControllerCompatApi21.fromToken(context,
49324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown                    session.getSessionToken().getToken());
49424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
49524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
49624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public MediaControllerImplApi21(Context context, MediaSessionCompat.Token sessionToken)
49724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown                throws RemoteException {
49824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            // TODO: refactor framework implementation
4995c41750574ba65da432b69f89cd32dc356281005RoboErik            mControllerObj = MediaControllerCompatApi21.fromToken(context,
50024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown                    sessionToken.getToken());
50124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            if (mControllerObj == null) throw new RemoteException();
50224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
50324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
50424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        @Override
50524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public void addCallback(Callback callback, Handler handler) {
50624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            MediaControllerCompatApi21.addCallback(mControllerObj, callback.mCallbackObj, handler);
50724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
50824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
50924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        @Override
51024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public void removeCallback(Callback callback) {
51124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            MediaControllerCompatApi21.removeCallback(mControllerObj, callback.mCallbackObj);
51224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
51324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
51424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        @Override
51524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public boolean dispatchMediaButtonEvent(KeyEvent event) {
51624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            return MediaControllerCompatApi21.dispatchMediaButtonEvent(mControllerObj, event);
51724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
51824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
51924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        @Override
52024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public TransportControls getTransportControls() {
5211435afe32073dee10e721dfb6122ce6a194a6412RoboErik            Object controlsObj = MediaControllerCompatApi21.getTransportControls(mControllerObj);
52224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            return controlsObj != null ? new TransportControlsApi21(controlsObj) : null;
52324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
52424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
52524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        @Override
52624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public PlaybackStateCompat getPlaybackState() {
52724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            Object stateObj = MediaControllerCompatApi21.getPlaybackState(mControllerObj);
52824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            return stateObj != null ? PlaybackStateCompat.fromPlaybackState(stateObj) : null;
52924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
53024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
53124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        @Override
53224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public MediaMetadataCompat getMetadata() {
53324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            Object metadataObj = MediaControllerCompatApi21.getMetadata(mControllerObj);
53424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            return metadataObj != null ? MediaMetadataCompat.fromMediaMetadata(metadataObj) : null;
53524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
53624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
53724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        @Override
53824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public int getRatingType() {
53924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            return MediaControllerCompatApi21.getRatingType(mControllerObj);
54024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
54124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
54224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        @Override
54324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public VolumeInfo getVolumeInfo() {
54424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            Object volumeInfoObj = MediaControllerCompatApi21.getVolumeInfo(mControllerObj);
54524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            return volumeInfoObj != null ? new VolumeInfo(
54624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown                    MediaControllerCompatApi21.VolumeInfo.getVolumeType(volumeInfoObj),
5471435afe32073dee10e721dfb6122ce6a194a6412RoboErik                    MediaControllerCompatApi21.VolumeInfo.getLegacyAudioStream(volumeInfoObj),
54824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown                    MediaControllerCompatApi21.VolumeInfo.getVolumeControl(volumeInfoObj),
54924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown                    MediaControllerCompatApi21.VolumeInfo.getMaxVolume(volumeInfoObj),
55024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown                    MediaControllerCompatApi21.VolumeInfo.getCurrentVolume(volumeInfoObj)) : null;
55124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
55224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
55324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        @Override
554b530c89bba371d2d575f10480b2e90914b0d3f3fGabriel Peal        public void sendCommand(String command, Bundle params, ResultReceiver cb) {
555b530c89bba371d2d575f10480b2e90914b0d3f3fGabriel Peal            MediaControllerCompatApi21.sendCommand(mControllerObj, command, params, cb);
55624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
55724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
55824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        @Override
55924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public Object getMediaController() {
56024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            return mControllerObj;
56124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
56224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    }
56324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
56424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    static class TransportControlsApi21 extends TransportControls {
56524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        private final Object mControlsObj;
56624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
56724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public TransportControlsApi21(Object controlsObj) {
56824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            mControlsObj = controlsObj;
56924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
57024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
57124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        @Override
57224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public void play() {
57324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            MediaControllerCompatApi21.TransportControls.play(mControlsObj);
57424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
57524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
57624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        @Override
57724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public void pause() {
57824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            MediaControllerCompatApi21.TransportControls.pause(mControlsObj);
57924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
58024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
58124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        @Override
58224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public void stop() {
58324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            MediaControllerCompatApi21.TransportControls.stop(mControlsObj);
58424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
58524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
58624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        @Override
58724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public void seekTo(long pos) {
58824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            MediaControllerCompatApi21.TransportControls.seekTo(mControlsObj, pos);
58924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
59024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
59124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        @Override
59224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public void fastForward() {
59324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            MediaControllerCompatApi21.TransportControls.fastForward(mControlsObj);
59424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
59524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
59624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        @Override
59724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public void rewind() {
59824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            MediaControllerCompatApi21.TransportControls.rewind(mControlsObj);
59924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
60024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
60124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        @Override
60224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public void skipToNext() {
60324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            MediaControllerCompatApi21.TransportControls.skipToNext(mControlsObj);
60424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
60524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
60624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        @Override
60724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public void skipToPrevious() {
60824fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            MediaControllerCompatApi21.TransportControls.skipToPrevious(mControlsObj);
60924fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
61024fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown
61124fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        @Override
61224fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        public void setRating(RatingCompat rating) {
61324fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown            MediaControllerCompatApi21.TransportControls.setRating(mControlsObj,
61424fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown                    rating != null ? rating.getRating() : null);
61524fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown        }
61624fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown    }
61724fa6c0dd42df057729e1a258388183f94da7f82Jeff Brown}
618