1a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown/*
2a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown * Copyright (C) 2013 The Android Open Source Project
3a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown *
4a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown * Licensed under the Apache License, Version 2.0 (the "License");
5a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown * you may not use this file except in compliance with the License.
6a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown * You may obtain a copy of the License at
7a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown *
8a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown *      http://www.apache.org/licenses/LICENSE-2.0
9a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown *
10a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown * Unless required by applicable law or agreed to in writing, software
11a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown * distributed under the License is distributed on an "AS IS" BASIS,
12a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown * See the License for the specific language governing permissions and
14a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown * limitations under the License.
15a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown */
16a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brownpackage android.support.v7.media;
17a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown
18a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brownimport android.app.PendingIntent;
19a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brownimport android.content.BroadcastReceiver;
20a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brownimport android.content.Context;
21a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brownimport android.content.Intent;
22a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brownimport android.content.IntentFilter;
23a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brownimport android.net.Uri;
24a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brownimport android.os.Bundle;
25a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brownimport android.util.Log;
26a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown
27dd5a10666ad2c33be5763215b5859f0298394357Sungsoo Limimport java.util.Iterator;
28dd5a10666ad2c33be5763215b5859f0298394357Sungsoo Lim
29a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown/**
30a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown * A helper class for playing media on remote routes using the remote playback protocol
31a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown * defined by {@link MediaControlIntent}.
32a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown * <p>
33a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown * The client maintains session state and offers a simplified interface for issuing
34a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown * remote playback media control intents to a single route.
35a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown * </p>
36a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown */
37a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brownpublic class RemotePlaybackClient {
38e2c6a94b6e4aab502f9b88dd3ff664bd90b25839Aurimas Liutikas    static final String TAG = "RemotePlaybackClient";
39e2c6a94b6e4aab502f9b88dd3ff664bd90b25839Aurimas Liutikas    static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
40a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown
41a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown    private final Context mContext;
42a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown    private final MediaRouter.RouteInfo mRoute;
43dd5a10666ad2c33be5763215b5859f0298394357Sungsoo Lim    private final ActionReceiver mActionReceiver;
44a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown    private final PendingIntent mItemStatusPendingIntent;
45a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown    private final PendingIntent mSessionStatusPendingIntent;
4639c5ca8cf8a45e9c550ef3732e36976b63812593Sungsoo Lim    private final PendingIntent mMessagePendingIntent;
47a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown
48a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown    private boolean mRouteSupportsRemotePlayback;
49a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown    private boolean mRouteSupportsQueuing;
50a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown    private boolean mRouteSupportsSessionManagement;
5139c5ca8cf8a45e9c550ef3732e36976b63812593Sungsoo Lim    private boolean mRouteSupportsMessaging;
52a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown
53e2c6a94b6e4aab502f9b88dd3ff664bd90b25839Aurimas Liutikas    String mSessionId;
54e2c6a94b6e4aab502f9b88dd3ff664bd90b25839Aurimas Liutikas    StatusCallback mStatusCallback;
55e2c6a94b6e4aab502f9b88dd3ff664bd90b25839Aurimas Liutikas    OnMessageReceivedListener mOnMessageReceivedListener;
56a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown
57a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown    /**
58a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * Creates a remote playback client for a route.
59a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     *
60a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * @param route The media route.
61a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     */
62a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown    public RemotePlaybackClient(Context context, MediaRouter.RouteInfo route) {
63a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        if (context == null) {
64a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown            throw new IllegalArgumentException("context must not be null");
65a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        }
66a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        if (route == null) {
67a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown            throw new IllegalArgumentException("route must not be null");
68a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        }
69a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown
70a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        mContext = context;
71a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        mRoute = route;
72a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown
73dd5a10666ad2c33be5763215b5859f0298394357Sungsoo Lim        IntentFilter actionFilter = new IntentFilter();
74dd5a10666ad2c33be5763215b5859f0298394357Sungsoo Lim        actionFilter.addAction(ActionReceiver.ACTION_ITEM_STATUS_CHANGED);
75dd5a10666ad2c33be5763215b5859f0298394357Sungsoo Lim        actionFilter.addAction(ActionReceiver.ACTION_SESSION_STATUS_CHANGED);
7639c5ca8cf8a45e9c550ef3732e36976b63812593Sungsoo Lim        actionFilter.addAction(ActionReceiver.ACTION_MESSAGE_RECEIVED);
77dd5a10666ad2c33be5763215b5859f0298394357Sungsoo Lim        mActionReceiver = new ActionReceiver();
78dd5a10666ad2c33be5763215b5859f0298394357Sungsoo Lim        context.registerReceiver(mActionReceiver, actionFilter);
79a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown
80dd5a10666ad2c33be5763215b5859f0298394357Sungsoo Lim        Intent itemStatusIntent = new Intent(ActionReceiver.ACTION_ITEM_STATUS_CHANGED);
81a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        itemStatusIntent.setPackage(context.getPackageName());
82a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        mItemStatusPendingIntent = PendingIntent.getBroadcast(
83a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                context, 0, itemStatusIntent, 0);
84a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown
85dd5a10666ad2c33be5763215b5859f0298394357Sungsoo Lim        Intent sessionStatusIntent = new Intent(ActionReceiver.ACTION_SESSION_STATUS_CHANGED);
86a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        sessionStatusIntent.setPackage(context.getPackageName());
87a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        mSessionStatusPendingIntent = PendingIntent.getBroadcast(
88a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                context, 0, sessionStatusIntent, 0);
89a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown
9039c5ca8cf8a45e9c550ef3732e36976b63812593Sungsoo Lim        Intent messageIntent = new Intent(ActionReceiver.ACTION_MESSAGE_RECEIVED);
9139c5ca8cf8a45e9c550ef3732e36976b63812593Sungsoo Lim        messageIntent.setPackage(context.getPackageName());
9239c5ca8cf8a45e9c550ef3732e36976b63812593Sungsoo Lim        mMessagePendingIntent = PendingIntent.getBroadcast(
9339c5ca8cf8a45e9c550ef3732e36976b63812593Sungsoo Lim                context, 0, messageIntent, 0);
94a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        detectFeatures();
95a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown    }
96a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown
97a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown    /**
98a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * Releases resources owned by the client.
99a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     */
100a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown    public void release() {
101dd5a10666ad2c33be5763215b5859f0298394357Sungsoo Lim        mContext.unregisterReceiver(mActionReceiver);
102a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown    }
103a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown
104a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown    /**
105a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * Returns true if the route supports remote playback.
106a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * <p>
107a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * If the route does not support remote playback, then none of the functionality
108a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * offered by the client will be available.
109a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * </p><p>
110a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * This method returns true if the route supports all of the following
111a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * actions: {@link MediaControlIntent#ACTION_PLAY play},
112a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * {@link MediaControlIntent#ACTION_SEEK seek},
113a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * {@link MediaControlIntent#ACTION_GET_STATUS get status},
114a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * {@link MediaControlIntent#ACTION_PAUSE pause},
115a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * {@link MediaControlIntent#ACTION_RESUME resume},
116a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * {@link MediaControlIntent#ACTION_STOP stop}.
117a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * </p>
118a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     *
119a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * @return True if remote playback is supported.
120a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     */
121a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown    public boolean isRemotePlaybackSupported() {
122a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        return mRouteSupportsRemotePlayback;
123a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown    }
124a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown
125a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown    /**
126a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * Returns true if the route supports queuing features.
127a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * <p>
128a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * If the route does not support queuing, then at most one media item can be played
129a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * at a time and the {@link #enqueue} method will not be available.
130a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * </p><p>
131a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * This method returns true if the route supports all of the basic remote playback
132a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * actions and all of the following actions:
133a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * {@link MediaControlIntent#ACTION_ENQUEUE enqueue},
134a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * {@link MediaControlIntent#ACTION_REMOVE remove}.
135a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * </p>
136a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     *
137a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * @return True if queuing is supported.  Implies {@link #isRemotePlaybackSupported}
138a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * is also true.
139a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     *
140a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * @see #isRemotePlaybackSupported
141a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     */
142a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown    public boolean isQueuingSupported() {
143a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        return mRouteSupportsQueuing;
144a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown    }
145a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown
146a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown    /**
147a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * Returns true if the route supports session management features.
148a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * <p>
149a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * If the route does not support session management, then the session will
150a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * not be created until the first media item is played.
151a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * </p><p>
152a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * This method returns true if the route supports all of the basic remote playback
153a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * actions and all of the following actions:
154a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * {@link MediaControlIntent#ACTION_START_SESSION start session},
155a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * {@link MediaControlIntent#ACTION_GET_SESSION_STATUS get session status},
156a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * {@link MediaControlIntent#ACTION_END_SESSION end session}.
157a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * </p>
158a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     *
159a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * @return True if session management is supported.
160a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * Implies {@link #isRemotePlaybackSupported} is also true.
161a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     *
162a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * @see #isRemotePlaybackSupported
163a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     */
164a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown    public boolean isSessionManagementSupported() {
165a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        return mRouteSupportsSessionManagement;
166a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown    }
167a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown
168a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown    /**
16939c5ca8cf8a45e9c550ef3732e36976b63812593Sungsoo Lim     * Returns true if the route supports messages.
170dd5a10666ad2c33be5763215b5859f0298394357Sungsoo Lim     * <p>
171dd5a10666ad2c33be5763215b5859f0298394357Sungsoo Lim     * This method returns true if the route supports all of the basic remote playback
172dd5a10666ad2c33be5763215b5859f0298394357Sungsoo Lim     * actions and all of the following actions:
173dd5a10666ad2c33be5763215b5859f0298394357Sungsoo Lim     * {@link MediaControlIntent#ACTION_START_SESSION start session},
17439c5ca8cf8a45e9c550ef3732e36976b63812593Sungsoo Lim     * {@link MediaControlIntent#ACTION_SEND_MESSAGE send message},
175dd5a10666ad2c33be5763215b5859f0298394357Sungsoo Lim     * {@link MediaControlIntent#ACTION_END_SESSION end session}.
176dd5a10666ad2c33be5763215b5859f0298394357Sungsoo Lim     * </p>
177dd5a10666ad2c33be5763215b5859f0298394357Sungsoo Lim     *
178dd5a10666ad2c33be5763215b5859f0298394357Sungsoo Lim     * @return True if session management is supported.
179dd5a10666ad2c33be5763215b5859f0298394357Sungsoo Lim     * Implies {@link #isRemotePlaybackSupported} is also true.
180dd5a10666ad2c33be5763215b5859f0298394357Sungsoo Lim     *
181dd5a10666ad2c33be5763215b5859f0298394357Sungsoo Lim     * @see #isRemotePlaybackSupported
182dd5a10666ad2c33be5763215b5859f0298394357Sungsoo Lim     */
18339c5ca8cf8a45e9c550ef3732e36976b63812593Sungsoo Lim    public boolean isMessagingSupported() {
18439c5ca8cf8a45e9c550ef3732e36976b63812593Sungsoo Lim        return mRouteSupportsMessaging;
185dd5a10666ad2c33be5763215b5859f0298394357Sungsoo Lim    }
186dd5a10666ad2c33be5763215b5859f0298394357Sungsoo Lim
187dd5a10666ad2c33be5763215b5859f0298394357Sungsoo Lim    /**
188a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * Gets the current session id if there is one.
189a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     *
190a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * @return The current session id, or null if none.
191a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     */
192a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown    public String getSessionId() {
193a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        return mSessionId;
194a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown    }
195a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown
196a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown    /**
197a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * Sets the current session id.
198a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * <p>
199a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * It is usually not necessary to set the session id explicitly since
200a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * it is created as a side-effect of other requests such as
201a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * {@link #play}, {@link #enqueue}, and {@link #startSession}.
202a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * </p>
203a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     *
204a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * @param sessionId The new session id, or null if none.
205a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     */
206a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown    public void setSessionId(String sessionId) {
207a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        if (mSessionId != sessionId
208a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                && (mSessionId == null || !mSessionId.equals(sessionId))) {
209a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown            if (DEBUG) {
210a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                Log.d(TAG, "Session id is now: " + sessionId);
211a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown            }
212a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown            mSessionId = sessionId;
213a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown            if (mStatusCallback != null) {
214a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                mStatusCallback.onSessionChanged(sessionId);
215a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown            }
216a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        }
217a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown    }
218a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown
219a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown    /**
220a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * Returns true if the client currently has a session.
221a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * <p>
222a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * Equivalent to checking whether {@link #getSessionId} returns a non-null result.
223a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * </p>
224a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     *
225a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * @return True if there is a current session.
226a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     */
227a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown    public boolean hasSession() {
228a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        return mSessionId != null;
229a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown    }
230a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown
231a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown    /**
232a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * Sets a callback that should receive status updates when the state of
233a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * media sessions or media items created by this instance of the remote
234a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * playback client changes.
235a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * <p>
236a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * The callback should be set before the session is created or any play
237a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * commands are issued.
238a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * </p>
239a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     *
240a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * @param callback The callback to set.  May be null to remove the previous callback.
241a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     */
242a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown    public void setStatusCallback(StatusCallback callback) {
243a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        mStatusCallback = callback;
244a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown    }
245a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown
246a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown    /**
24739c5ca8cf8a45e9c550ef3732e36976b63812593Sungsoo Lim     * Sets a callback that should receive messages when a message is sent from
248dd5a10666ad2c33be5763215b5859f0298394357Sungsoo Lim     * media sessions created by this instance of the remote playback client changes.
249dd5a10666ad2c33be5763215b5859f0298394357Sungsoo Lim     * <p>
250dd5a10666ad2c33be5763215b5859f0298394357Sungsoo Lim     * The callback should be set before the session is created.
251dd5a10666ad2c33be5763215b5859f0298394357Sungsoo Lim     * </p>
252dd5a10666ad2c33be5763215b5859f0298394357Sungsoo Lim     *
253718625bf6d666a657f8b4e1969f02ef62a21bfc1Sungsoo Lim     * @param listener The callback to set.  May be null to remove the previous callback.
254dd5a10666ad2c33be5763215b5859f0298394357Sungsoo Lim     */
255718625bf6d666a657f8b4e1969f02ef62a21bfc1Sungsoo Lim    public void setOnMessageReceivedListener(OnMessageReceivedListener listener) {
256718625bf6d666a657f8b4e1969f02ef62a21bfc1Sungsoo Lim        mOnMessageReceivedListener = listener;
257dd5a10666ad2c33be5763215b5859f0298394357Sungsoo Lim    }
258dd5a10666ad2c33be5763215b5859f0298394357Sungsoo Lim
259dd5a10666ad2c33be5763215b5859f0298394357Sungsoo Lim    /**
260a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * Sends a request to play a media item.
261a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * <p>
262a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * Clears the queue and starts playing the new item immediately.  If the queue
263a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * was previously paused, then it is resumed as a side-effect of this request.
264a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * </p><p>
265a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * The request is issued in the current session.  If no session is available, then
266a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * one is created implicitly.
267a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * </p><p>
268a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * Please refer to {@link MediaControlIntent#ACTION_PLAY ACTION_PLAY} for
269a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * more information about the semantics of this request.
270a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * </p>
271a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     *
272a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * @param contentUri The content Uri to play.
273a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * @param mimeType The mime type of the content, or null if unknown.
274a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * @param positionMillis The initial content position for the item in milliseconds,
275a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * or <code>0</code> to start at the beginning.
276a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * @param metadata The media item metadata bundle, or null if none.
277a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * @param extras A bundle of extra arguments to be added to the
278a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * {@link MediaControlIntent#ACTION_PLAY} intent, or null if none.
279a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * @param callback A callback to invoke when the request has been
280a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * processed, or null if none.
281a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     *
282a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * @throws UnsupportedOperationException if the route does not support remote playback.
283a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     *
284a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * @see MediaControlIntent#ACTION_PLAY
285a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * @see #isRemotePlaybackSupported
286a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     */
287a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown    public void play(Uri contentUri, String mimeType, Bundle metadata,
288a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown            long positionMillis, Bundle extras, ItemActionCallback callback) {
289a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        playOrEnqueue(contentUri, mimeType, metadata, positionMillis,
290a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                extras, callback, MediaControlIntent.ACTION_PLAY);
291a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown    }
292a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown
293a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown    /**
294a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * Sends a request to enqueue a media item.
295a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * <p>
296a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * Enqueues a new item to play.  If the queue was previously paused, then will
297a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * remain paused.
298a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * </p><p>
299a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * The request is issued in the current session.  If no session is available, then
300a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * one is created implicitly.
301a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * </p><p>
302a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * Please refer to {@link MediaControlIntent#ACTION_ENQUEUE ACTION_ENQUEUE} for
303a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * more information about the semantics of this request.
304a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * </p>
305a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     *
306a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * @param contentUri The content Uri to enqueue.
307a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * @param mimeType The mime type of the content, or null if unknown.
308a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * @param positionMillis The initial content position for the item in milliseconds,
309a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * or <code>0</code> to start at the beginning.
310a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * @param metadata The media item metadata bundle, or null if none.
311a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * @param extras A bundle of extra arguments to be added to the
312a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * {@link MediaControlIntent#ACTION_ENQUEUE} intent, or null if none.
313a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * @param callback A callback to invoke when the request has been
314a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * processed, or null if none.
315a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     *
316a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * @throws UnsupportedOperationException if the route does not support queuing.
317a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     *
318a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * @see MediaControlIntent#ACTION_ENQUEUE
319a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * @see #isRemotePlaybackSupported
320a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * @see #isQueuingSupported
321a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     */
322a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown    public void enqueue(Uri contentUri, String mimeType, Bundle metadata,
323a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown            long positionMillis, Bundle extras, ItemActionCallback callback) {
324a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        playOrEnqueue(contentUri, mimeType, metadata, positionMillis,
325a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                extras, callback, MediaControlIntent.ACTION_ENQUEUE);
326a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown    }
327a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown
328a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown    private void playOrEnqueue(Uri contentUri, String mimeType, Bundle metadata,
329a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown            long positionMillis, Bundle extras,
330a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown            final ItemActionCallback callback, String action) {
331a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        if (contentUri == null) {
332a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown            throw new IllegalArgumentException("contentUri must not be null");
333a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        }
334a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        throwIfRemotePlaybackNotSupported();
335a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        if (action.equals(MediaControlIntent.ACTION_ENQUEUE)) {
336a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown            throwIfQueuingNotSupported();
337a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        }
338a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown
339a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        Intent intent = new Intent(action);
340a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        intent.setDataAndType(contentUri, mimeType);
341a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        intent.putExtra(MediaControlIntent.EXTRA_ITEM_STATUS_UPDATE_RECEIVER,
342a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                mItemStatusPendingIntent);
343a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        if (metadata != null) {
344a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown            intent.putExtra(MediaControlIntent.EXTRA_ITEM_METADATA, metadata);
345a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        }
346a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        if (positionMillis != 0) {
347a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown            intent.putExtra(MediaControlIntent.EXTRA_ITEM_CONTENT_POSITION, positionMillis);
348a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        }
349a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        performItemAction(intent, mSessionId, null, extras, callback);
350a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown    }
351a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown
352a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown    /**
353a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * Sends a request to seek to a new position in a media item.
354a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * <p>
355a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * Seeks to a new position.  If the queue was previously paused then it
356a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * remains paused but the item's new position is still remembered.
357a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * </p><p>
358a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * The request is issued in the current session.
359a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * </p><p>
360a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * Please refer to {@link MediaControlIntent#ACTION_SEEK ACTION_SEEK} for
361a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * more information about the semantics of this request.
362a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * </p>
363a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     *
364a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * @param itemId The item id.
365a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * @param positionMillis The new content position for the item in milliseconds,
366a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * or <code>0</code> to start at the beginning.
367a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * @param extras A bundle of extra arguments to be added to the
368a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * {@link MediaControlIntent#ACTION_SEEK} intent, or null if none.
369a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * @param callback A callback to invoke when the request has been
370a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * processed, or null if none.
371a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     *
372a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * @throws IllegalStateException if there is no current session.
373a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     *
374a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * @see MediaControlIntent#ACTION_SEEK
375a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * @see #isRemotePlaybackSupported
376a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     */
377a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown    public void seek(String itemId, long positionMillis, Bundle extras,
378a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown            ItemActionCallback callback) {
379a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        if (itemId == null) {
380a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown            throw new IllegalArgumentException("itemId must not be null");
381a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        }
382a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        throwIfNoCurrentSession();
383a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown
384a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        Intent intent = new Intent(MediaControlIntent.ACTION_SEEK);
385a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        intent.putExtra(MediaControlIntent.EXTRA_ITEM_CONTENT_POSITION, positionMillis);
386a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        performItemAction(intent, mSessionId, itemId, extras, callback);
387a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown    }
388a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown
389a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown    /**
390a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * Sends a request to get the status of a media item.
391a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * <p>
392a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * The request is issued in the current session.
393a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * </p><p>
394a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * Please refer to {@link MediaControlIntent#ACTION_GET_STATUS ACTION_GET_STATUS} for
395a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * more information about the semantics of this request.
396a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * </p>
397a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     *
398a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * @param itemId The item id.
399a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * @param extras A bundle of extra arguments to be added to the
400a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * {@link MediaControlIntent#ACTION_GET_STATUS} intent, or null if none.
401a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * @param callback A callback to invoke when the request has been
402a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * processed, or null if none.
403a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     *
404a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * @throws IllegalStateException if there is no current session.
405a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     *
406a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * @see MediaControlIntent#ACTION_GET_STATUS
407a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * @see #isRemotePlaybackSupported
408a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     */
409a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown    public void getStatus(String itemId, Bundle extras, ItemActionCallback callback) {
410a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        if (itemId == null) {
411a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown            throw new IllegalArgumentException("itemId must not be null");
412a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        }
413a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        throwIfNoCurrentSession();
414a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown
415a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        Intent intent = new Intent(MediaControlIntent.ACTION_GET_STATUS);
416a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        performItemAction(intent, mSessionId, itemId, extras, callback);
417a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown    }
418a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown
419a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown    /**
420a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * Sends a request to remove a media item from the queue.
421a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * <p>
422a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * The request is issued in the current session.
423a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * </p><p>
424a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * Please refer to {@link MediaControlIntent#ACTION_REMOVE ACTION_REMOVE} for
425a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * more information about the semantics of this request.
426a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * </p>
427a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     *
428a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * @param itemId The item id.
429a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * @param extras A bundle of extra arguments to be added to the
430a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * {@link MediaControlIntent#ACTION_REMOVE} intent, or null if none.
431a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * @param callback A callback to invoke when the request has been
432a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * processed, or null if none.
433a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     *
434a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * @throws IllegalStateException if there is no current session.
435a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * @throws UnsupportedOperationException if the route does not support queuing.
436a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     *
437a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * @see MediaControlIntent#ACTION_REMOVE
438a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * @see #isRemotePlaybackSupported
439a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * @see #isQueuingSupported
440a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     */
441a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown    public void remove(String itemId, Bundle extras, ItemActionCallback callback) {
442a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        if (itemId == null) {
443a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown            throw new IllegalArgumentException("itemId must not be null");
444a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        }
445a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        throwIfQueuingNotSupported();
446a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        throwIfNoCurrentSession();
447a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown
448a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        Intent intent = new Intent(MediaControlIntent.ACTION_REMOVE);
449a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        performItemAction(intent, mSessionId, itemId, extras, callback);
450a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown    }
451a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown
452a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown    /**
453a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * Sends a request to pause media playback.
454a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * <p>
455a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * The request is issued in the current session.  If playback is already paused
456a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * then the request has no effect.
457a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * </p><p>
458a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * Please refer to {@link MediaControlIntent#ACTION_PAUSE ACTION_PAUSE} for
459a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * more information about the semantics of this request.
460a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * </p>
461a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     *
462a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * @param extras A bundle of extra arguments to be added to the
463a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * {@link MediaControlIntent#ACTION_PAUSE} intent, or null if none.
464a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * @param callback A callback to invoke when the request has been
465a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * processed, or null if none.
466a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     *
467a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * @throws IllegalStateException if there is no current session.
468a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     *
469a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * @see MediaControlIntent#ACTION_PAUSE
470a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * @see #isRemotePlaybackSupported
471a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     */
472a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown    public void pause(Bundle extras, SessionActionCallback callback) {
473a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        throwIfNoCurrentSession();
474a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown
475a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        Intent intent = new Intent(MediaControlIntent.ACTION_PAUSE);
476a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        performSessionAction(intent, mSessionId, extras, callback);
477a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown    }
478a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown
479a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown    /**
480a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * Sends a request to resume (unpause) media playback.
481a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * <p>
482a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * The request is issued in the current session.  If playback is not paused
483a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * then the request has no effect.
484a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * </p><p>
485a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * Please refer to {@link MediaControlIntent#ACTION_RESUME ACTION_RESUME} for
486a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * more information about the semantics of this request.
487a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * </p>
488a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     *
489a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * @param extras A bundle of extra arguments to be added to the
490a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * {@link MediaControlIntent#ACTION_RESUME} intent, or null if none.
491a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * @param callback A callback to invoke when the request has been
492a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * processed, or null if none.
493a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     *
494a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * @throws IllegalStateException if there is no current session.
495a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     *
496a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * @see MediaControlIntent#ACTION_RESUME
497a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * @see #isRemotePlaybackSupported
498a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     */
499a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown    public void resume(Bundle extras, SessionActionCallback callback) {
500a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        throwIfNoCurrentSession();
501a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown
502a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        Intent intent = new Intent(MediaControlIntent.ACTION_RESUME);
503a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        performSessionAction(intent, mSessionId, extras, callback);
504a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown    }
505a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown
506a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown    /**
507a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * Sends a request to stop media playback and clear the media playback queue.
508a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * <p>
509a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * The request is issued in the current session.  If the queue is already
510a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * empty then the request has no effect.
511a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * </p><p>
512a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * Please refer to {@link MediaControlIntent#ACTION_STOP ACTION_STOP} for
513a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * more information about the semantics of this request.
514a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * </p>
515a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     *
516a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * @param extras A bundle of extra arguments to be added to the
517a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * {@link MediaControlIntent#ACTION_STOP} intent, or null if none.
518a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * @param callback A callback to invoke when the request has been
519a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * processed, or null if none.
520a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     *
521a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * @throws IllegalStateException if there is no current session.
522a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     *
523a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * @see MediaControlIntent#ACTION_STOP
524a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * @see #isRemotePlaybackSupported
525a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     */
526a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown    public void stop(Bundle extras, SessionActionCallback callback) {
527a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        throwIfNoCurrentSession();
528a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown
529a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        Intent intent = new Intent(MediaControlIntent.ACTION_STOP);
530a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        performSessionAction(intent, mSessionId, extras, callback);
531a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown    }
532a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown
533a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown    /**
534a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * Sends a request to start a new media playback session.
535a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * <p>
536a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * The application must wait for the callback to indicate that this request
537a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * is complete before issuing other requests that affect the session.  If this
538a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * request is successful then the previous session will be invalidated.
539a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * </p><p>
540a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * Please refer to {@link MediaControlIntent#ACTION_START_SESSION ACTION_START_SESSION}
541a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * for more information about the semantics of this request.
542a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * </p>
543a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     *
544a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * @param extras A bundle of extra arguments to be added to the
545a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * {@link MediaControlIntent#ACTION_START_SESSION} intent, or null if none.
546a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * @param callback A callback to invoke when the request has been
547a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * processed, or null if none.
548a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     *
549a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * @throws UnsupportedOperationException if the route does not support session management.
550a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     *
551a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * @see MediaControlIntent#ACTION_START_SESSION
552a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * @see #isRemotePlaybackSupported
553a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * @see #isSessionManagementSupported
554a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     */
555a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown    public void startSession(Bundle extras, SessionActionCallback callback) {
556a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        throwIfSessionManagementNotSupported();
557a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown
558a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        Intent intent = new Intent(MediaControlIntent.ACTION_START_SESSION);
559a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        intent.putExtra(MediaControlIntent.EXTRA_SESSION_STATUS_UPDATE_RECEIVER,
560a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                mSessionStatusPendingIntent);
56139c5ca8cf8a45e9c550ef3732e36976b63812593Sungsoo Lim        if (mRouteSupportsMessaging) {
56239c5ca8cf8a45e9c550ef3732e36976b63812593Sungsoo Lim            intent.putExtra(MediaControlIntent.EXTRA_MESSAGE_RECEIVER, mMessagePendingIntent);
563dd5a10666ad2c33be5763215b5859f0298394357Sungsoo Lim        }
564a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        performSessionAction(intent, null, extras, callback);
565a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown    }
566a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown
567a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown    /**
56839c5ca8cf8a45e9c550ef3732e36976b63812593Sungsoo Lim     * Sends a message.
569dd5a10666ad2c33be5763215b5859f0298394357Sungsoo Lim     * <p>
570dd5a10666ad2c33be5763215b5859f0298394357Sungsoo Lim     * The request is issued in the current session.
571dd5a10666ad2c33be5763215b5859f0298394357Sungsoo Lim     * </p><p>
57239c5ca8cf8a45e9c550ef3732e36976b63812593Sungsoo Lim     * Please refer to {@link MediaControlIntent#ACTION_SEND_MESSAGE} for
573dd5a10666ad2c33be5763215b5859f0298394357Sungsoo Lim     * more information about the semantics of this request.
574dd5a10666ad2c33be5763215b5859f0298394357Sungsoo Lim     * </p>
575dd5a10666ad2c33be5763215b5859f0298394357Sungsoo Lim     *
576718625bf6d666a657f8b4e1969f02ef62a21bfc1Sungsoo Lim     * @param message A bundle message denoting {@link MediaControlIntent#EXTRA_MESSAGE}.
577dd5a10666ad2c33be5763215b5859f0298394357Sungsoo Lim     * @param callback A callback to invoke when the request has been processed, or null if none.
578dd5a10666ad2c33be5763215b5859f0298394357Sungsoo Lim     *
579dd5a10666ad2c33be5763215b5859f0298394357Sungsoo Lim     * @throws IllegalStateException if there is no current session.
58039c5ca8cf8a45e9c550ef3732e36976b63812593Sungsoo Lim     * @throws UnsupportedOperationException if the route does not support messages.
581dd5a10666ad2c33be5763215b5859f0298394357Sungsoo Lim     *
58239c5ca8cf8a45e9c550ef3732e36976b63812593Sungsoo Lim     * @see MediaControlIntent#ACTION_SEND_MESSAGE
58339c5ca8cf8a45e9c550ef3732e36976b63812593Sungsoo Lim     * @see #isMessagingSupported
584dd5a10666ad2c33be5763215b5859f0298394357Sungsoo Lim     */
58539c5ca8cf8a45e9c550ef3732e36976b63812593Sungsoo Lim    public void sendMessage(Bundle message, SessionActionCallback callback) {
586dd5a10666ad2c33be5763215b5859f0298394357Sungsoo Lim        throwIfNoCurrentSession();
58739c5ca8cf8a45e9c550ef3732e36976b63812593Sungsoo Lim        throwIfMessageNotSupported();
588dd5a10666ad2c33be5763215b5859f0298394357Sungsoo Lim
58939c5ca8cf8a45e9c550ef3732e36976b63812593Sungsoo Lim        Intent intent = new Intent(MediaControlIntent.ACTION_SEND_MESSAGE);
590dd5a10666ad2c33be5763215b5859f0298394357Sungsoo Lim        performSessionAction(intent, mSessionId, message, callback);
591dd5a10666ad2c33be5763215b5859f0298394357Sungsoo Lim    }
592dd5a10666ad2c33be5763215b5859f0298394357Sungsoo Lim
593dd5a10666ad2c33be5763215b5859f0298394357Sungsoo Lim    /**
594a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * Sends a request to get the status of the media playback session.
595a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * <p>
596a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * The request is issued in the current session.
597a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * </p><p>
598a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * Please refer to {@link MediaControlIntent#ACTION_GET_SESSION_STATUS
599a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * ACTION_GET_SESSION_STATUS} for more information about the semantics of this request.
600a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * </p>
601a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     *
602a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * @param extras A bundle of extra arguments to be added to the
603a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * {@link MediaControlIntent#ACTION_GET_SESSION_STATUS} intent, or null if none.
604a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * @param callback A callback to invoke when the request has been
605a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * processed, or null if none.
606a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     *
607a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * @throws IllegalStateException if there is no current session.
608a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * @throws UnsupportedOperationException if the route does not support session management.
609a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     *
610a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * @see MediaControlIntent#ACTION_GET_SESSION_STATUS
611a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * @see #isRemotePlaybackSupported
612a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * @see #isSessionManagementSupported
613a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     */
614a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown    public void getSessionStatus(Bundle extras, SessionActionCallback callback) {
615a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        throwIfSessionManagementNotSupported();
616a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        throwIfNoCurrentSession();
617a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown
618a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        Intent intent = new Intent(MediaControlIntent.ACTION_GET_SESSION_STATUS);
619a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        performSessionAction(intent, mSessionId, extras, callback);
620a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown    }
621a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown
622a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown    /**
623a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * Sends a request to end the media playback session.
624a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * <p>
625a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * The request is issued in the current session.  If this request is successful,
626a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * the {@link #getSessionId session id property} will be set to null after
627a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * the callback is invoked.
628a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * </p><p>
629a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * Please refer to {@link MediaControlIntent#ACTION_END_SESSION ACTION_END_SESSION}
630a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * for more information about the semantics of this request.
631a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * </p>
632a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     *
633a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * @param extras A bundle of extra arguments to be added to the
634a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * {@link MediaControlIntent#ACTION_END_SESSION} intent, or null if none.
635a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * @param callback A callback to invoke when the request has been
636a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * processed, or null if none.
637a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     *
638a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * @throws IllegalStateException if there is no current session.
639a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * @throws UnsupportedOperationException if the route does not support session management.
640a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     *
641a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * @see MediaControlIntent#ACTION_END_SESSION
642a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * @see #isRemotePlaybackSupported
643a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * @see #isSessionManagementSupported
644a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     */
645a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown    public void endSession(Bundle extras, SessionActionCallback callback) {
646a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        throwIfSessionManagementNotSupported();
647a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        throwIfNoCurrentSession();
648a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown
649a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        Intent intent = new Intent(MediaControlIntent.ACTION_END_SESSION);
650a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        performSessionAction(intent, mSessionId, extras, callback);
651a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown    }
652a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown
653a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown    private void performItemAction(final Intent intent,
654a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown            final String sessionId, final String itemId,
655a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown            Bundle extras, final ItemActionCallback callback) {
656a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        intent.addCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK);
657a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        if (sessionId != null) {
658a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown            intent.putExtra(MediaControlIntent.EXTRA_SESSION_ID, sessionId);
659a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        }
660a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        if (itemId != null) {
661a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown            intent.putExtra(MediaControlIntent.EXTRA_ITEM_ID, itemId);
662a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        }
663a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        if (extras != null) {
664a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown            intent.putExtras(extras);
665a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        }
666a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        logRequest(intent);
667a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        mRoute.sendControlRequest(intent, new MediaRouter.ControlRequestCallback() {
668a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown            @Override
669a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown            public void onResult(Bundle data) {
670a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                if (data != null) {
671a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                    String sessionIdResult = inferMissingResult(sessionId,
672a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                            data.getString(MediaControlIntent.EXTRA_SESSION_ID));
673a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                    MediaSessionStatus sessionStatus = MediaSessionStatus.fromBundle(
674a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                            data.getBundle(MediaControlIntent.EXTRA_SESSION_STATUS));
675a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                    String itemIdResult = inferMissingResult(itemId,
676a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                            data.getString(MediaControlIntent.EXTRA_ITEM_ID));
677a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                    MediaItemStatus itemStatus = MediaItemStatus.fromBundle(
678a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                            data.getBundle(MediaControlIntent.EXTRA_ITEM_STATUS));
679a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                    adoptSession(sessionIdResult);
680a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                    if (sessionIdResult != null && itemIdResult != null && itemStatus != null) {
681a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                        if (DEBUG) {
682a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                            Log.d(TAG, "Received result from " + intent.getAction()
683a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                                    + ": data=" + bundleToString(data)
684a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                                    + ", sessionId=" + sessionIdResult
685a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                                    + ", sessionStatus=" + sessionStatus
686a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                                    + ", itemId=" + itemIdResult
687a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                                    + ", itemStatus=" + itemStatus);
688a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                        }
689a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                        callback.onResult(data, sessionIdResult, sessionStatus,
690a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                                itemIdResult, itemStatus);
691a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                        return;
692a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                    }
693a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                }
694a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                handleInvalidResult(intent, callback, data);
695a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown            }
696a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown
697a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown            @Override
698a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown            public void onError(String error, Bundle data) {
699a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                handleError(intent, callback, error, data);
700a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown            }
701a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        });
702a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown    }
703a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown
704a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown    private void performSessionAction(final Intent intent, final String sessionId,
705a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown            Bundle extras, final SessionActionCallback callback) {
706a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        intent.addCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK);
707a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        if (sessionId != null) {
708a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown            intent.putExtra(MediaControlIntent.EXTRA_SESSION_ID, sessionId);
709a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        }
710a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        if (extras != null) {
711a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown            intent.putExtras(extras);
712a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        }
713a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        logRequest(intent);
714a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        mRoute.sendControlRequest(intent, new MediaRouter.ControlRequestCallback() {
715a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown            @Override
716a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown            public void onResult(Bundle data) {
717a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                if (data != null) {
718a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                    String sessionIdResult = inferMissingResult(sessionId,
719a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                            data.getString(MediaControlIntent.EXTRA_SESSION_ID));
720a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                    MediaSessionStatus sessionStatus = MediaSessionStatus.fromBundle(
721a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                            data.getBundle(MediaControlIntent.EXTRA_SESSION_STATUS));
722a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                    adoptSession(sessionIdResult);
723a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                    if (sessionIdResult != null) {
724a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                        if (DEBUG) {
725a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                            Log.d(TAG, "Received result from " + intent.getAction()
726a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                                    + ": data=" + bundleToString(data)
727a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                                    + ", sessionId=" + sessionIdResult
728a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                                    + ", sessionStatus=" + sessionStatus);
729a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                        }
730a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                        try {
731a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                            callback.onResult(data, sessionIdResult, sessionStatus);
732a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                        } finally {
733a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                            if (intent.getAction().equals(MediaControlIntent.ACTION_END_SESSION)
734a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                                    && sessionIdResult.equals(mSessionId)) {
735a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                                setSessionId(null);
736a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                            }
737a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                        }
738a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                        return;
739a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                    }
740a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                }
741a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                handleInvalidResult(intent, callback, data);
742a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown            }
743a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown
744a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown            @Override
745a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown            public void onError(String error, Bundle data) {
746a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                handleError(intent, callback, error, data);
747a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown            }
748a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        });
749a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown    }
750a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown
751e2c6a94b6e4aab502f9b88dd3ff664bd90b25839Aurimas Liutikas    void adoptSession(String sessionId) {
752a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        if (sessionId != null) {
753a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown            setSessionId(sessionId);
754a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        }
755a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown    }
756a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown
757e2c6a94b6e4aab502f9b88dd3ff664bd90b25839Aurimas Liutikas    void handleInvalidResult(Intent intent, ActionCallback callback,
758a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown            Bundle data) {
759a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        Log.w(TAG, "Received invalid result data from " + intent.getAction()
760a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                + ": data=" + bundleToString(data));
761a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        callback.onError(null, MediaControlIntent.ERROR_UNKNOWN, data);
762a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown    }
763a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown
764e2c6a94b6e4aab502f9b88dd3ff664bd90b25839Aurimas Liutikas    void handleError(Intent intent, ActionCallback callback,
765a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown            String error, Bundle data) {
766a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        final int code;
767a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        if (data != null) {
768a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown            code = data.getInt(MediaControlIntent.EXTRA_ERROR_CODE,
769a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                    MediaControlIntent.ERROR_UNKNOWN);
770a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        } else {
771a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown            code = MediaControlIntent.ERROR_UNKNOWN;
772a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        }
773a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        if (DEBUG) {
774a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown            Log.w(TAG, "Received error from " + intent.getAction()
775a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                    + ": error=" + error
776a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                    + ", code=" + code
777a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                    + ", data=" + bundleToString(data));
778a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        }
779a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        callback.onError(error, code, data);
780a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown    }
781a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown
782a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown    private void detectFeatures() {
783a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        mRouteSupportsRemotePlayback = routeSupportsAction(MediaControlIntent.ACTION_PLAY)
784a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                && routeSupportsAction(MediaControlIntent.ACTION_SEEK)
785a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                && routeSupportsAction(MediaControlIntent.ACTION_GET_STATUS)
786a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                && routeSupportsAction(MediaControlIntent.ACTION_PAUSE)
787a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                && routeSupportsAction(MediaControlIntent.ACTION_RESUME)
788a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                && routeSupportsAction(MediaControlIntent.ACTION_STOP);
789a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        mRouteSupportsQueuing = mRouteSupportsRemotePlayback
790a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                && routeSupportsAction(MediaControlIntent.ACTION_ENQUEUE)
791a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                && routeSupportsAction(MediaControlIntent.ACTION_REMOVE);
792a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        mRouteSupportsSessionManagement = mRouteSupportsRemotePlayback
793a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                && routeSupportsAction(MediaControlIntent.ACTION_START_SESSION)
794a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                && routeSupportsAction(MediaControlIntent.ACTION_GET_SESSION_STATUS)
795a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                && routeSupportsAction(MediaControlIntent.ACTION_END_SESSION);
79639c5ca8cf8a45e9c550ef3732e36976b63812593Sungsoo Lim        mRouteSupportsMessaging = doesRouteSupportMessaging();
797a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown    }
798a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown
799a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown    private boolean routeSupportsAction(String action) {
800a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        return mRoute.supportsControlAction(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK, action);
801a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown    }
802a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown
80339c5ca8cf8a45e9c550ef3732e36976b63812593Sungsoo Lim    private boolean doesRouteSupportMessaging() {
804dd5a10666ad2c33be5763215b5859f0298394357Sungsoo Lim        for (IntentFilter filter : mRoute.getControlFilters()) {
80539c5ca8cf8a45e9c550ef3732e36976b63812593Sungsoo Lim            if (filter.hasAction(MediaControlIntent.ACTION_SEND_MESSAGE)) {
80639c5ca8cf8a45e9c550ef3732e36976b63812593Sungsoo Lim                return true;
807dd5a10666ad2c33be5763215b5859f0298394357Sungsoo Lim            }
808dd5a10666ad2c33be5763215b5859f0298394357Sungsoo Lim        }
809dd5a10666ad2c33be5763215b5859f0298394357Sungsoo Lim        return false;
810dd5a10666ad2c33be5763215b5859f0298394357Sungsoo Lim    }
811dd5a10666ad2c33be5763215b5859f0298394357Sungsoo Lim
812a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown    private void throwIfRemotePlaybackNotSupported() {
813a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        if (!mRouteSupportsRemotePlayback) {
814a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown            throw new UnsupportedOperationException("The route does not support remote playback.");
815a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        }
816a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown    }
817a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown
818a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown    private void throwIfQueuingNotSupported() {
819a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        if (!mRouteSupportsQueuing) {
820a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown            throw new UnsupportedOperationException("The route does not support queuing.");
821a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        }
822a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown    }
823a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown
824a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown    private void throwIfSessionManagementNotSupported() {
825a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        if (!mRouteSupportsSessionManagement) {
826a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown            throw new UnsupportedOperationException("The route does not support "
827a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                    + "session management.");
828a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        }
829a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown    }
830a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown
83139c5ca8cf8a45e9c550ef3732e36976b63812593Sungsoo Lim    private void throwIfMessageNotSupported() {
83239c5ca8cf8a45e9c550ef3732e36976b63812593Sungsoo Lim        if (!mRouteSupportsMessaging) {
83339c5ca8cf8a45e9c550ef3732e36976b63812593Sungsoo Lim            throw new UnsupportedOperationException("The route does not support message.");
834dd5a10666ad2c33be5763215b5859f0298394357Sungsoo Lim        }
835dd5a10666ad2c33be5763215b5859f0298394357Sungsoo Lim    }
836dd5a10666ad2c33be5763215b5859f0298394357Sungsoo Lim
837a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown    private void throwIfNoCurrentSession() {
838a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        if (mSessionId == null) {
839a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown            throw new IllegalStateException("There is no current session.");
840a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        }
841a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown    }
842a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown
843e2c6a94b6e4aab502f9b88dd3ff664bd90b25839Aurimas Liutikas    static String inferMissingResult(String request, String result) {
844a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        if (result == null) {
845a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown            // Result is missing.
846a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown            return request;
847a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        }
848a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        if (request == null || request.equals(result)) {
849a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown            // Request didn't specify a value or result matches request.
850a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown            return result;
851a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        }
852a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        // Result conflicts with request.
853a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        return null;
854a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown    }
855a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown
856a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown    private static void logRequest(Intent intent) {
857a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        if (DEBUG) {
858a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown            Log.d(TAG, "Sending request: " + intent);
859a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        }
860a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown    }
861a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown
862e2c6a94b6e4aab502f9b88dd3ff664bd90b25839Aurimas Liutikas    static String bundleToString(Bundle bundle) {
863a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        if (bundle != null) {
864a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown            bundle.size(); // force bundle to be unparcelled
865a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown            return bundle.toString();
866a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        }
867a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        return "null";
868a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown    }
869a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown
870dd5a10666ad2c33be5763215b5859f0298394357Sungsoo Lim    private final class ActionReceiver extends BroadcastReceiver {
871a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        public static final String ACTION_ITEM_STATUS_CHANGED =
872a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                "android.support.v7.media.actions.ACTION_ITEM_STATUS_CHANGED";
873a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        public static final String ACTION_SESSION_STATUS_CHANGED =
874a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                "android.support.v7.media.actions.ACTION_SESSION_STATUS_CHANGED";
87539c5ca8cf8a45e9c550ef3732e36976b63812593Sungsoo Lim        public static final String ACTION_MESSAGE_RECEIVED =
87639c5ca8cf8a45e9c550ef3732e36976b63812593Sungsoo Lim                "android.support.v7.media.actions.ACTION_MESSAGE_RECEIVED";
877a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown
878e2c6a94b6e4aab502f9b88dd3ff664bd90b25839Aurimas Liutikas        ActionReceiver() {
879e2c6a94b6e4aab502f9b88dd3ff664bd90b25839Aurimas Liutikas        }
880e2c6a94b6e4aab502f9b88dd3ff664bd90b25839Aurimas Liutikas
881a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        @Override
882a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        public void onReceive(Context context, Intent intent) {
883a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown            String sessionId = intent.getStringExtra(MediaControlIntent.EXTRA_SESSION_ID);
884a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown            if (sessionId == null || !sessionId.equals(mSessionId)) {
885a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                Log.w(TAG, "Discarding spurious status callback "
886a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                        + "with missing or invalid session id: sessionId=" + sessionId);
887a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                return;
888a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown            }
889a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown
890a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown            MediaSessionStatus sessionStatus = MediaSessionStatus.fromBundle(
891a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                    intent.getBundleExtra(MediaControlIntent.EXTRA_SESSION_STATUS));
892a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown            String action = intent.getAction();
893a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown            if (action.equals(ACTION_ITEM_STATUS_CHANGED)) {
894a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                String itemId = intent.getStringExtra(MediaControlIntent.EXTRA_ITEM_ID);
895a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                if (itemId == null) {
896a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                    Log.w(TAG, "Discarding spurious status callback with missing item id.");
897a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                    return;
898a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                }
899a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown
900a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                MediaItemStatus itemStatus = MediaItemStatus.fromBundle(
901a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                        intent.getBundleExtra(MediaControlIntent.EXTRA_ITEM_STATUS));
902a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                if (itemStatus == null) {
903a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                    Log.w(TAG, "Discarding spurious status callback with missing item status.");
904a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                    return;
905a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                }
906a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown
907a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                if (DEBUG) {
908a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                    Log.d(TAG, "Received item status callback: sessionId=" + sessionId
909a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                            + ", sessionStatus=" + sessionStatus
910a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                            + ", itemId=" + itemId
911a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                            + ", itemStatus=" + itemStatus);
912a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                }
913a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown
914a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                if (mStatusCallback != null) {
915a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                    mStatusCallback.onItemStatusChanged(intent.getExtras(),
916a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                            sessionId, sessionStatus, itemId, itemStatus);
917a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                }
918a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown            } else if (action.equals(ACTION_SESSION_STATUS_CHANGED)) {
919a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                if (sessionStatus == null) {
920a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                    Log.w(TAG, "Discarding spurious media status callback with "
921a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                            +"missing session status.");
922a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                    return;
923a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                }
924a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown
925a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                if (DEBUG) {
926a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                    Log.d(TAG, "Received session status callback: sessionId=" + sessionId
927a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                            + ", sessionStatus=" + sessionStatus);
928a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                }
929a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown
930a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                if (mStatusCallback != null) {
931a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                    mStatusCallback.onSessionStatusChanged(intent.getExtras(),
932a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                            sessionId, sessionStatus);
933a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                }
93439c5ca8cf8a45e9c550ef3732e36976b63812593Sungsoo Lim            } else if (action.equals(ACTION_MESSAGE_RECEIVED)) {
935dd5a10666ad2c33be5763215b5859f0298394357Sungsoo Lim                if (DEBUG) {
93639c5ca8cf8a45e9c550ef3732e36976b63812593Sungsoo Lim                    Log.d(TAG, "Received message callback: sessionId=" + sessionId);
937dd5a10666ad2c33be5763215b5859f0298394357Sungsoo Lim                }
938dd5a10666ad2c33be5763215b5859f0298394357Sungsoo Lim
939718625bf6d666a657f8b4e1969f02ef62a21bfc1Sungsoo Lim                if (mOnMessageReceivedListener != null) {
940718625bf6d666a657f8b4e1969f02ef62a21bfc1Sungsoo Lim                    mOnMessageReceivedListener.onMessageReceived(sessionId,
94139c5ca8cf8a45e9c550ef3732e36976b63812593Sungsoo Lim                            intent.getBundleExtra(MediaControlIntent.EXTRA_MESSAGE));
942dd5a10666ad2c33be5763215b5859f0298394357Sungsoo Lim                }
943a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown            }
944a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        }
945a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown    }
946a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown
947a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown    /**
948a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * A callback that will receive media status updates.
949a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     */
950a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown    public static abstract class StatusCallback {
951a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        /**
952a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown         * Called when the status of a media item changes.
953a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown         *
954a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown         * @param data The result data bundle.
955a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown         * @param sessionId The session id.
956a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown         * @param sessionStatus The session status, or null if unknown.
957a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown         * @param itemId The item id.
958a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown         * @param itemStatus The item status.
959a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown         */
960a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        public void onItemStatusChanged(Bundle data,
961a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                String sessionId, MediaSessionStatus sessionStatus,
962a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                String itemId, MediaItemStatus itemStatus) {
963a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        }
964a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown
965a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        /**
966a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown         * Called when the status of a media session changes.
967a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown         *
968a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown         * @param data The result data bundle.
969a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown         * @param sessionId The session id.
970a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown         * @param sessionStatus The session status, or null if unknown.
971a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown         */
972a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        public void onSessionStatusChanged(Bundle data,
973a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                String sessionId, MediaSessionStatus sessionStatus) {
974a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        }
975a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown
976a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        /**
977a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown         * Called when the session of the remote playback client changes.
978a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown         *
979a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown         * @param sessionId The new session id.
980a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown         */
981a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        public void onSessionChanged(String sessionId) {
982a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        }
983a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown    }
984a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown
985a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown    /**
986a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * Base callback type for remote playback requests.
987a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     */
988a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown    public static abstract class ActionCallback {
989a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        /**
990a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown         * Called when a media control request fails.
991a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown         *
992a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown         * @param error A localized error message which may be shown to the user, or null
993a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown         * if the cause of the error is unclear.
994a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown         * @param code The error code, or {@link MediaControlIntent#ERROR_UNKNOWN} if unknown.
995a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown         * @param data The error data bundle, or null if none.
996a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown         */
997a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        public void onError(String error, int code, Bundle data) {
998a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        }
999a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown    }
1000a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown
1001a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown    /**
1002a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * Callback for remote playback requests that operate on items.
1003a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     */
1004a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown    public static abstract class ItemActionCallback extends ActionCallback {
1005a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        /**
1006a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown         * Called when the request succeeds.
1007a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown         *
1008a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown         * @param data The result data bundle.
1009a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown         * @param sessionId The session id.
1010a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown         * @param sessionStatus The session status, or null if unknown.
1011a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown         * @param itemId The item id.
1012a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown         * @param itemStatus The item status.
1013a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown         */
1014a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        public void onResult(Bundle data, String sessionId, MediaSessionStatus sessionStatus,
1015a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown                String itemId, MediaItemStatus itemStatus) {
1016a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        }
1017a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown    }
1018a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown
1019a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown    /**
1020a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     * Callback for remote playback requests that operate on sessions.
1021a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown     */
1022a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown    public static abstract class SessionActionCallback extends ActionCallback {
1023a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        /**
1024a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown         * Called when the request succeeds.
1025a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown         *
1026a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown         * @param data The result data bundle.
1027a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown         * @param sessionId The session id.
1028a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown         * @param sessionStatus The session status, or null if unknown.
1029a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown         */
1030a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        public void onResult(Bundle data, String sessionId, MediaSessionStatus sessionStatus) {
1031a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown        }
1032a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown    }
1033718625bf6d666a657f8b4e1969f02ef62a21bfc1Sungsoo Lim
1034718625bf6d666a657f8b4e1969f02ef62a21bfc1Sungsoo Lim    /**
1035718625bf6d666a657f8b4e1969f02ef62a21bfc1Sungsoo Lim     * A callback that will receive messages from media sessions.
1036718625bf6d666a657f8b4e1969f02ef62a21bfc1Sungsoo Lim     */
1037718625bf6d666a657f8b4e1969f02ef62a21bfc1Sungsoo Lim    public interface OnMessageReceivedListener {
1038718625bf6d666a657f8b4e1969f02ef62a21bfc1Sungsoo Lim        /**
1039718625bf6d666a657f8b4e1969f02ef62a21bfc1Sungsoo Lim         * Called when a message received.
1040718625bf6d666a657f8b4e1969f02ef62a21bfc1Sungsoo Lim         *
1041718625bf6d666a657f8b4e1969f02ef62a21bfc1Sungsoo Lim         * @param sessionId The session id.
1042718625bf6d666a657f8b4e1969f02ef62a21bfc1Sungsoo Lim         * @param message A bundle message denoting {@link MediaControlIntent#EXTRA_MESSAGE}.
1043718625bf6d666a657f8b4e1969f02ef62a21bfc1Sungsoo Lim         */
1044718625bf6d666a657f8b4e1969f02ef62a21bfc1Sungsoo Lim        void onMessageReceived(String sessionId, Bundle message);
1045718625bf6d666a657f8b4e1969f02ef62a21bfc1Sungsoo Lim    }
1046a97f1edf7624785c41ec0bfec6fd12c2388d9234Jeff Brown}
1047