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