19a1de308cea2d160778fd977825f10a07b49d738Adam Powell/* 29a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Copyright (C) 2012 The Android Open Source Project 39a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 49a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Licensed under the Apache License, Version 2.0 (the "License"); 59a1de308cea2d160778fd977825f10a07b49d738Adam Powell * you may not use this file except in compliance with the License. 69a1de308cea2d160778fd977825f10a07b49d738Adam Powell * You may obtain a copy of the License at 79a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 89a1de308cea2d160778fd977825f10a07b49d738Adam Powell * http://www.apache.org/licenses/LICENSE-2.0 99a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 109a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Unless required by applicable law or agreed to in writing, software 119a1de308cea2d160778fd977825f10a07b49d738Adam Powell * distributed under the License is distributed on an "AS IS" BASIS, 129a1de308cea2d160778fd977825f10a07b49d738Adam Powell * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 139a1de308cea2d160778fd977825f10a07b49d738Adam Powell * See the License for the specific language governing permissions and 149a1de308cea2d160778fd977825f10a07b49d738Adam Powell * limitations under the License. 159a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 169a1de308cea2d160778fd977825f10a07b49d738Adam Powell 179a1de308cea2d160778fd977825f10a07b49d738Adam Powellpackage android.media; 189a1de308cea2d160778fd977825f10a07b49d738Adam Powell 198e37a85bf3dc39519942698dc90a3951306b934bAdam Powellimport android.content.BroadcastReceiver; 209a1de308cea2d160778fd977825f10a07b49d738Adam Powellimport android.content.Context; 218e37a85bf3dc39519942698dc90a3951306b934bAdam Powellimport android.content.Intent; 228e37a85bf3dc39519942698dc90a3951306b934bAdam Powellimport android.content.IntentFilter; 23b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackbornimport android.content.res.Resources; 24ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powellimport android.graphics.drawable.Drawable; 25705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powellimport android.hardware.display.DisplayManager; 26705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powellimport android.hardware.display.WifiDisplay; 27705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powellimport android.hardware.display.WifiDisplayStatus; 289a1de308cea2d160778fd977825f10a07b49d738Adam Powellimport android.os.Handler; 29632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackbornimport android.os.IBinder; 30632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackbornimport android.os.RemoteException; 31632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackbornimport android.os.ServiceManager; 32632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackbornimport android.text.TextUtils; 339a1de308cea2d160778fd977825f10a07b49d738Adam Powellimport android.util.Log; 34705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powellimport android.view.Display; 359a1de308cea2d160778fd977825f10a07b49d738Adam Powell 369a1de308cea2d160778fd977825f10a07b49d738Adam Powellimport java.util.ArrayList; 379a1de308cea2d160778fd977825f10a07b49d738Adam Powellimport java.util.HashMap; 38d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powellimport java.util.List; 3939d5c6172503620ac3761148adac5fd7fa20d02dAdam Powellimport java.util.concurrent.CopyOnWriteArrayList; 409a1de308cea2d160778fd977825f10a07b49d738Adam Powell 419a1de308cea2d160778fd977825f10a07b49d738Adam Powell/** 429a1de308cea2d160778fd977825f10a07b49d738Adam Powell * MediaRouter allows applications to control the routing of media channels 439a1de308cea2d160778fd977825f10a07b49d738Adam Powell * and streams from the current device to external speakers and destination devices. 449a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 45b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn * <p>A MediaRouter is retrieved through {@link Context#getSystemService(String) 46b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn * Context.getSystemService()} of a {@link Context#MEDIA_ROUTER_SERVICE 47b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn * Context.MEDIA_ROUTER_SERVICE}. 48b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn * 49b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn * <p>The media router API is not thread-safe; all interactions with it must be 50b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn * done from the main thread of the process.</p> 519a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 529a1de308cea2d160778fd977825f10a07b49d738Adam Powellpublic class MediaRouter { 539a1de308cea2d160778fd977825f10a07b49d738Adam Powell private static final String TAG = "MediaRouter"; 549a1de308cea2d160778fd977825f10a07b49d738Adam Powell 5592130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown static class Static implements DisplayManager.DisplayListener { 56b35c445f34e1a18e17aef3e3dfbc1c39b4d1815cAdam Powell final Resources mResources; 57632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn final IAudioService mAudioService; 58705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell final DisplayManager mDisplayService; 59b35c445f34e1a18e17aef3e3dfbc1c39b4d1815cAdam Powell final Handler mHandler; 6039d5c6172503620ac3761148adac5fd7fa20d02dAdam Powell final CopyOnWriteArrayList<CallbackInfo> mCallbacks = 6139d5c6172503620ac3761148adac5fd7fa20d02dAdam Powell new CopyOnWriteArrayList<CallbackInfo>(); 62b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn 63b35c445f34e1a18e17aef3e3dfbc1c39b4d1815cAdam Powell final ArrayList<RouteInfo> mRoutes = new ArrayList<RouteInfo>(); 64b35c445f34e1a18e17aef3e3dfbc1c39b4d1815cAdam Powell final ArrayList<RouteCategory> mCategories = new ArrayList<RouteCategory>(); 65b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn 66b35c445f34e1a18e17aef3e3dfbc1c39b4d1815cAdam Powell final RouteCategory mSystemCategory; 67632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn 68705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell final AudioRoutesInfo mCurAudioRoutesInfo = new AudioRoutesInfo(); 69b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn 70705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell RouteInfo mDefaultAudioVideo; 71b35c445f34e1a18e17aef3e3dfbc1c39b4d1815cAdam Powell RouteInfo mBluetoothA2dpRoute; 72b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn 73b35c445f34e1a18e17aef3e3dfbc1c39b4d1815cAdam Powell RouteInfo mSelectedRoute; 749a1de308cea2d160778fd977825f10a07b49d738Adam Powell 75705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell WifiDisplayStatus mLastKnownWifiDisplayStatus; 76705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 77705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell final IAudioRoutesObserver.Stub mAudioRoutesObserver = new IAudioRoutesObserver.Stub() { 78632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn public void dispatchAudioRoutesChanged(final AudioRoutesInfo newRoutes) { 79632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn mHandler.post(new Runnable() { 80632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn @Override public void run() { 81705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell updateAudioRoutes(newRoutes); 82632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } 83632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn }); 84632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } 85632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn }; 86632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn 87b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn Static(Context appContext) { 88b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn mResources = Resources.getSystem(); 89b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn mHandler = new Handler(appContext.getMainLooper()); 909a1de308cea2d160778fd977825f10a07b49d738Adam Powell 91632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn IBinder b = ServiceManager.getService(Context.AUDIO_SERVICE); 92632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn mAudioService = IAudioService.Stub.asInterface(b); 939a1de308cea2d160778fd977825f10a07b49d738Adam Powell 94705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell mDisplayService = (DisplayManager) appContext.getSystemService(Context.DISPLAY_SERVICE); 95705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 96dd0a19266d5c837069da1ea188744d54c8d723a8Adam Powell mSystemCategory = new RouteCategory( 97dd0a19266d5c837069da1ea188744d54c8d723a8Adam Powell com.android.internal.R.string.default_audio_route_category_name, 98705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell ROUTE_TYPE_LIVE_AUDIO | ROUTE_TYPE_LIVE_VIDEO, false); 99705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell mSystemCategory.mIsSystem = true; 100b35c445f34e1a18e17aef3e3dfbc1c39b4d1815cAdam Powell } 101b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn 102b35c445f34e1a18e17aef3e3dfbc1c39b4d1815cAdam Powell // Called after sStatic is initialized 1038e37a85bf3dc39519942698dc90a3951306b934bAdam Powell void startMonitoringRoutes(Context appContext) { 104705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell mDefaultAudioVideo = new RouteInfo(mSystemCategory); 105705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell mDefaultAudioVideo.mNameResId = com.android.internal.R.string.default_audio_route_name; 106705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell mDefaultAudioVideo.mSupportedTypes = ROUTE_TYPE_LIVE_AUDIO | ROUTE_TYPE_LIVE_VIDEO; 10792130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown mDefaultAudioVideo.mPresentationDisplay = choosePresentationDisplayForRoute( 10892130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown mDefaultAudioVideo, getAllPresentationDisplays()); 1092ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell addRouteStatic(mDefaultAudioVideo); 110632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn 1112ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell // This will select the active wifi display route if there is one. 1122ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell updateWifiDisplayStatus(mDisplayService.getWifiDisplayStatus()); 1132ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell 1142ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell appContext.registerReceiver(new WifiDisplayStatusChangedReceiver(), 1152ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell new IntentFilter(DisplayManager.ACTION_WIFI_DISPLAY_STATUS_CHANGED)); 1168e37a85bf3dc39519942698dc90a3951306b934bAdam Powell appContext.registerReceiver(new VolumeChangeReceiver(), 1178e37a85bf3dc39519942698dc90a3951306b934bAdam Powell new IntentFilter(AudioManager.VOLUME_CHANGED_ACTION)); 1188e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 11992130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown mDisplayService.registerDisplayListener(this, mHandler); 12092130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown 121705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell AudioRoutesInfo newAudioRoutes = null; 122632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn try { 123705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell newAudioRoutes = mAudioService.startWatchingRoutes(mAudioRoutesObserver); 124632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } catch (RemoteException e) { 125632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } 126705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell if (newAudioRoutes != null) { 1272ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell // This will select the active BT route if there is one and the current 1282ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell // selected route is the default system route, or if there is no selected 1292ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell // route yet. 130705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell updateAudioRoutes(newAudioRoutes); 131632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } 132705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 1332ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell // Select the default route if the above didn't sync us up 1342ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell // appropriately with relevant system state. 1352ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell if (mSelectedRoute == null) { 1362ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell selectRouteStatic(mDefaultAudioVideo.getSupportedTypes(), mDefaultAudioVideo); 1372ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell } 138632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } 139632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn 140705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell void updateAudioRoutes(AudioRoutesInfo newRoutes) { 141705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell if (newRoutes.mMainType != mCurAudioRoutesInfo.mMainType) { 142705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell mCurAudioRoutesInfo.mMainType = newRoutes.mMainType; 143632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn int name; 144632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn if ((newRoutes.mMainType&AudioRoutesInfo.MAIN_HEADPHONES) != 0 145632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn || (newRoutes.mMainType&AudioRoutesInfo.MAIN_HEADSET) != 0) { 146632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn name = com.android.internal.R.string.default_audio_route_name_headphones; 147632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } else if ((newRoutes.mMainType&AudioRoutesInfo.MAIN_DOCK_SPEAKERS) != 0) { 148632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn name = com.android.internal.R.string.default_audio_route_name_dock_speakers; 149632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } else if ((newRoutes.mMainType&AudioRoutesInfo.MAIN_HDMI) != 0) { 1504131a37366d59b5e61f55c4e48d2b22ee0c4cad4Adam Powell name = com.android.internal.R.string.default_media_route_name_hdmi; 151632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } else { 152632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn name = com.android.internal.R.string.default_audio_route_name; 153632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } 154705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell sStatic.mDefaultAudioVideo.mNameResId = name; 155705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell dispatchRouteChanged(sStatic.mDefaultAudioVideo); 156632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } 157bcf21e913af7252fb1994e07b6cf179321ecd049Adam Powell 1583f369684e13dfea0ba8ea134f3e95930b0dd7df0Adam Powell final int mainType = mCurAudioRoutesInfo.mMainType; 1593f369684e13dfea0ba8ea134f3e95930b0dd7df0Adam Powell 160bcf21e913af7252fb1994e07b6cf179321ecd049Adam Powell boolean a2dpEnabled; 161bcf21e913af7252fb1994e07b6cf179321ecd049Adam Powell try { 162bcf21e913af7252fb1994e07b6cf179321ecd049Adam Powell a2dpEnabled = mAudioService.isBluetoothA2dpOn(); 163bcf21e913af7252fb1994e07b6cf179321ecd049Adam Powell } catch (RemoteException e) { 164bcf21e913af7252fb1994e07b6cf179321ecd049Adam Powell Log.e(TAG, "Error querying Bluetooth A2DP state", e); 165bcf21e913af7252fb1994e07b6cf179321ecd049Adam Powell a2dpEnabled = false; 166bcf21e913af7252fb1994e07b6cf179321ecd049Adam Powell } 167bcf21e913af7252fb1994e07b6cf179321ecd049Adam Powell 168705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell if (!TextUtils.equals(newRoutes.mBluetoothName, mCurAudioRoutesInfo.mBluetoothName)) { 169705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell mCurAudioRoutesInfo.mBluetoothName = newRoutes.mBluetoothName; 170705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell if (mCurAudioRoutesInfo.mBluetoothName != null) { 171632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn if (sStatic.mBluetoothA2dpRoute == null) { 172632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn final RouteInfo info = new RouteInfo(sStatic.mSystemCategory); 173705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell info.mName = mCurAudioRoutesInfo.mBluetoothName; 174632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn info.mSupportedTypes = ROUTE_TYPE_LIVE_AUDIO; 175632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn sStatic.mBluetoothA2dpRoute = info; 1762ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell addRouteStatic(sStatic.mBluetoothA2dpRoute); 177632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } else { 178705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell sStatic.mBluetoothA2dpRoute.mName = mCurAudioRoutesInfo.mBluetoothName; 179632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn dispatchRouteChanged(sStatic.mBluetoothA2dpRoute); 180632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } 181632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } else if (sStatic.mBluetoothA2dpRoute != null) { 182632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn removeRoute(sStatic.mBluetoothA2dpRoute); 183632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn sStatic.mBluetoothA2dpRoute = null; 184632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } 185632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } 186bcf21e913af7252fb1994e07b6cf179321ecd049Adam Powell 187bcf21e913af7252fb1994e07b6cf179321ecd049Adam Powell if (mBluetoothA2dpRoute != null) { 1883f369684e13dfea0ba8ea134f3e95930b0dd7df0Adam Powell if (mainType != AudioRoutesInfo.MAIN_SPEAKER && 1893f369684e13dfea0ba8ea134f3e95930b0dd7df0Adam Powell mSelectedRoute == mBluetoothA2dpRoute && !a2dpEnabled) { 190705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell selectRouteStatic(ROUTE_TYPE_LIVE_AUDIO, mDefaultAudioVideo); 1913f369684e13dfea0ba8ea134f3e95930b0dd7df0Adam Powell } else if ((mSelectedRoute == mDefaultAudioVideo || mSelectedRoute == null) && 1922ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell a2dpEnabled) { 193bcf21e913af7252fb1994e07b6cf179321ecd049Adam Powell selectRouteStatic(ROUTE_TYPE_LIVE_AUDIO, mBluetoothA2dpRoute); 194bcf21e913af7252fb1994e07b6cf179321ecd049Adam Powell } 195bcf21e913af7252fb1994e07b6cf179321ecd049Adam Powell } 196b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn } 19792130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown 19892130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown @Override 19992130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown public void onDisplayAdded(int displayId) { 20092130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown updatePresentationDisplays(displayId); 20192130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown } 20292130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown 20392130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown @Override 20492130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown public void onDisplayChanged(int displayId) { 20592130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown updatePresentationDisplays(displayId); 20692130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown } 20792130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown 20892130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown @Override 20992130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown public void onDisplayRemoved(int displayId) { 21092130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown updatePresentationDisplays(displayId); 21192130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown } 21292130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown 21392130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown public Display[] getAllPresentationDisplays() { 21492130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown return mDisplayService.getDisplays(DisplayManager.DISPLAY_CATEGORY_PRESENTATION); 21592130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown } 21692130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown 21792130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown private void updatePresentationDisplays(int changedDisplayId) { 21892130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown final Display[] displays = getAllPresentationDisplays(); 21992130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown final int count = mRoutes.size(); 22092130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown for (int i = 0; i < count; i++) { 22192130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown final RouteInfo info = mRoutes.get(i); 22292130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown Display display = choosePresentationDisplayForRoute(info, displays); 22392130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown if (display != info.mPresentationDisplay 22492130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown || (display != null && display.getDisplayId() == changedDisplayId)) { 22592130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown info.mPresentationDisplay = display; 22692130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown dispatchRoutePresentationDisplayChanged(info); 22792130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown } 22892130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown } 22992130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown } 230b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn } 2319a1de308cea2d160778fd977825f10a07b49d738Adam Powell 232b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn static Static sStatic; 2339a1de308cea2d160778fd977825f10a07b49d738Adam Powell 2349a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 2359a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Route type flag for live audio. 2369a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 2379a1de308cea2d160778fd977825f10a07b49d738Adam Powell * <p>A device that supports live audio routing will allow the media audio stream 2389a1de308cea2d160778fd977825f10a07b49d738Adam Powell * to be routed to supported destinations. This can include internal speakers or 2399a1de308cea2d160778fd977825f10a07b49d738Adam Powell * audio jacks on the device itself, A2DP devices, and more.</p> 2409a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 2419a1de308cea2d160778fd977825f10a07b49d738Adam Powell * <p>Once initiated this routing is transparent to the application. All audio 2429a1de308cea2d160778fd977825f10a07b49d738Adam Powell * played on the media stream will be routed to the selected destination.</p> 2439a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 2449a1de308cea2d160778fd977825f10a07b49d738Adam Powell public static final int ROUTE_TYPE_LIVE_AUDIO = 0x1; 2459a1de308cea2d160778fd977825f10a07b49d738Adam Powell 2469a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 247705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell * Route type flag for live video. 248705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell * 249705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell * <p>A device that supports live video routing will allow a mirrored version 250705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell * of the device's primary display or a customized 251705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell * {@link android.app.Presentation Presentation} to be routed to supported destinations.</p> 252705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell * 253705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell * <p>Once initiated, display mirroring is transparent to the application. 254705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell * While remote routing is active the application may use a 255705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell * {@link android.app.Presentation Presentation} to replace the mirrored view 256705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell * on the external display with different content.</p> 25792130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * 25892130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * @see RouteInfo#getPresentationDisplay() 25992130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * @see android.app.Presentation 260705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell */ 261705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell public static final int ROUTE_TYPE_LIVE_VIDEO = 0x2; 262705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 263705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell /** 2649a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Route type flag for application-specific usage. 2659a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 2669a1de308cea2d160778fd977825f10a07b49d738Adam Powell * <p>Unlike other media route types, user routes are managed by the application. 2679a1de308cea2d160778fd977825f10a07b49d738Adam Powell * The MediaRouter will manage and dispatch events for user routes, but the application 2689a1de308cea2d160778fd977825f10a07b49d738Adam Powell * is expected to interpret the meaning of these events and perform the requested 2699a1de308cea2d160778fd977825f10a07b49d738Adam Powell * routing tasks.</p> 2709a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 2719a1de308cea2d160778fd977825f10a07b49d738Adam Powell public static final int ROUTE_TYPE_USER = 0x00800000; 2729a1de308cea2d160778fd977825f10a07b49d738Adam Powell 2739a1de308cea2d160778fd977825f10a07b49d738Adam Powell // Maps application contexts 2749a1de308cea2d160778fd977825f10a07b49d738Adam Powell static final HashMap<Context, MediaRouter> sRouters = new HashMap<Context, MediaRouter>(); 2759a1de308cea2d160778fd977825f10a07b49d738Adam Powell 2769a1de308cea2d160778fd977825f10a07b49d738Adam Powell static String typesToString(int types) { 2779a1de308cea2d160778fd977825f10a07b49d738Adam Powell final StringBuilder result = new StringBuilder(); 2789a1de308cea2d160778fd977825f10a07b49d738Adam Powell if ((types & ROUTE_TYPE_LIVE_AUDIO) != 0) { 2799a1de308cea2d160778fd977825f10a07b49d738Adam Powell result.append("ROUTE_TYPE_LIVE_AUDIO "); 2809a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 2812bb7c122ef6ce8539dfbaeb3292adcd942185f82Bryan Mawhinney if ((types & ROUTE_TYPE_LIVE_VIDEO) != 0) { 2822bb7c122ef6ce8539dfbaeb3292adcd942185f82Bryan Mawhinney result.append("ROUTE_TYPE_LIVE_VIDEO "); 2832bb7c122ef6ce8539dfbaeb3292adcd942185f82Bryan Mawhinney } 2849a1de308cea2d160778fd977825f10a07b49d738Adam Powell if ((types & ROUTE_TYPE_USER) != 0) { 2859a1de308cea2d160778fd977825f10a07b49d738Adam Powell result.append("ROUTE_TYPE_USER "); 2869a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 2879a1de308cea2d160778fd977825f10a07b49d738Adam Powell return result.toString(); 2889a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 2899a1de308cea2d160778fd977825f10a07b49d738Adam Powell 290b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn /** @hide */ 291b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn public MediaRouter(Context context) { 292b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn synchronized (Static.class) { 293b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn if (sStatic == null) { 2948e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final Context appContext = context.getApplicationContext(); 2958e37a85bf3dc39519942698dc90a3951306b934bAdam Powell sStatic = new Static(appContext); 2968e37a85bf3dc39519942698dc90a3951306b934bAdam Powell sStatic.startMonitoringRoutes(appContext); 297b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn } 2989a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 2999a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 3009a1de308cea2d160778fd977825f10a07b49d738Adam Powell 301690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell /** 302690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell * @hide for use by framework routing UI 303690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell */ 304690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell public RouteInfo getSystemAudioRoute() { 305705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell return sStatic.mDefaultAudioVideo; 306690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell } 307690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell 308690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell /** 3094599696591f745b3a546197d2ba7e5cfc5562484Adam Powell * @hide for use by framework routing UI 3104599696591f745b3a546197d2ba7e5cfc5562484Adam Powell */ 3114599696591f745b3a546197d2ba7e5cfc5562484Adam Powell public RouteCategory getSystemAudioCategory() { 3124599696591f745b3a546197d2ba7e5cfc5562484Adam Powell return sStatic.mSystemCategory; 3134599696591f745b3a546197d2ba7e5cfc5562484Adam Powell } 3144599696591f745b3a546197d2ba7e5cfc5562484Adam Powell 3154599696591f745b3a546197d2ba7e5cfc5562484Adam Powell /** 316690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell * Return the currently selected route for the given types 317690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell * 318690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell * @param type route types 319690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell * @return the selected route 320690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell */ 321690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell public RouteInfo getSelectedRoute(int type) { 322b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn return sStatic.mSelectedRoute; 323690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell } 324690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell 3259a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 3269a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Add a callback to listen to events about specific kinds of media routes. 3279a1de308cea2d160778fd977825f10a07b49d738Adam Powell * If the specified callback is already registered, its registration will be updated for any 3289a1de308cea2d160778fd977825f10a07b49d738Adam Powell * additional route types specified. 3299a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 3309a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param types Types of routes this callback is interested in 3319a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param cb Callback to add 3329a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 3339a1de308cea2d160778fd977825f10a07b49d738Adam Powell public void addCallback(int types, Callback cb) { 334b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn final int count = sStatic.mCallbacks.size(); 3359a1de308cea2d160778fd977825f10a07b49d738Adam Powell for (int i = 0; i < count; i++) { 336b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn final CallbackInfo info = sStatic.mCallbacks.get(i); 3379a1de308cea2d160778fd977825f10a07b49d738Adam Powell if (info.cb == cb) { 338dbbfa702a09f6d2d36dee1b552442d04a4673f89Adam Powell info.type |= types; 3399a1de308cea2d160778fd977825f10a07b49d738Adam Powell return; 3409a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 3419a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 342b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn sStatic.mCallbacks.add(new CallbackInfo(cb, types, this)); 3439a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 3449a1de308cea2d160778fd977825f10a07b49d738Adam Powell 3459a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 3469a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Remove the specified callback. It will no longer receive events about media routing. 3479a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 3489a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param cb Callback to remove 3499a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 3509a1de308cea2d160778fd977825f10a07b49d738Adam Powell public void removeCallback(Callback cb) { 351b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn final int count = sStatic.mCallbacks.size(); 3529a1de308cea2d160778fd977825f10a07b49d738Adam Powell for (int i = 0; i < count; i++) { 353b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn if (sStatic.mCallbacks.get(i).cb == cb) { 354b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn sStatic.mCallbacks.remove(i); 3559a1de308cea2d160778fd977825f10a07b49d738Adam Powell return; 3569a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 3579a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 3589a1de308cea2d160778fd977825f10a07b49d738Adam Powell Log.w(TAG, "removeCallback(" + cb + "): callback not registered"); 3599a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 3609a1de308cea2d160778fd977825f10a07b49d738Adam Powell 361d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell /** 362d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * Select the specified route to use for output of the given media types. 363d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * 364d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param types type flags indicating which types this route should be used for. 365d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * The route must support at least a subset. 366d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param route Route to select 367d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell */ 3689a1de308cea2d160778fd977825f10a07b49d738Adam Powell public void selectRoute(int types, RouteInfo route) { 3690d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell // Applications shouldn't programmatically change anything but user routes. 3700d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell types &= ROUTE_TYPE_USER; 3710d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell selectRouteStatic(types, route); 3720d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell } 3730d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell 3740d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell /** 3750d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * @hide internal use 3760d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell */ 3770d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public void selectRouteInt(int types, RouteInfo route) { 378b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn selectRouteStatic(types, route); 379b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn } 380b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn 381b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn static void selectRouteStatic(int types, RouteInfo route) { 382705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell final RouteInfo oldRoute = sStatic.mSelectedRoute; 383705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell if (oldRoute == route) return; 3840d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell if ((route.getSupportedTypes() & types) == 0) { 3850d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell Log.w(TAG, "selectRoute ignored; cannot select route with supported types " + 3860d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell typesToString(route.getSupportedTypes()) + " into route types " + 3870d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell typesToString(types)); 3884ee1f55ce0f4909a7430ab44563a81852f335071Adam Powell return; 3890d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell } 3909a1de308cea2d160778fd977825f10a07b49d738Adam Powell 391dd0a19266d5c837069da1ea188744d54c8d723a8Adam Powell final RouteInfo btRoute = sStatic.mBluetoothA2dpRoute; 392dd0a19266d5c837069da1ea188744d54c8d723a8Adam Powell if (btRoute != null && (types & ROUTE_TYPE_LIVE_AUDIO) != 0 && 393705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell (route == btRoute || route == sStatic.mDefaultAudioVideo)) { 394dd0a19266d5c837069da1ea188744d54c8d723a8Adam Powell try { 395dd0a19266d5c837069da1ea188744d54c8d723a8Adam Powell sStatic.mAudioService.setBluetoothA2dpOn(route == btRoute); 396dd0a19266d5c837069da1ea188744d54c8d723a8Adam Powell } catch (RemoteException e) { 397dd0a19266d5c837069da1ea188744d54c8d723a8Adam Powell Log.e(TAG, "Error changing Bluetooth A2DP state", e); 398dd0a19266d5c837069da1ea188744d54c8d723a8Adam Powell } 399dd0a19266d5c837069da1ea188744d54c8d723a8Adam Powell } 400dd0a19266d5c837069da1ea188744d54c8d723a8Adam Powell 401705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell final WifiDisplay activeDisplay = 402705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell sStatic.mDisplayService.getWifiDisplayStatus().getActiveDisplay(); 403705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell final boolean oldRouteHasAddress = oldRoute != null && oldRoute.mDeviceAddress != null; 404705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell final boolean newRouteHasAddress = route != null && route.mDeviceAddress != null; 405705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell if (activeDisplay != null || oldRouteHasAddress || newRouteHasAddress) { 406705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell if (newRouteHasAddress && !matchesDeviceAddress(activeDisplay, route)) { 407705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell sStatic.mDisplayService.connectWifiDisplay(route.mDeviceAddress); 408705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } else if (activeDisplay != null && !newRouteHasAddress) { 409705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell sStatic.mDisplayService.disconnectWifiDisplay(); 410705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 411705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 412705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 413705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell if (oldRoute != null) { 4149a1de308cea2d160778fd977825f10a07b49d738Adam Powell // TODO filter types properly 415705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell dispatchRouteUnselected(types & oldRoute.getSupportedTypes(), oldRoute); 4169a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 417b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn sStatic.mSelectedRoute = route; 4189a1de308cea2d160778fd977825f10a07b49d738Adam Powell if (route != null) { 4199a1de308cea2d160778fd977825f10a07b49d738Adam Powell // TODO filter types properly 4209a1de308cea2d160778fd977825f10a07b49d738Adam Powell dispatchRouteSelected(types & route.getSupportedTypes(), route); 4219a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 4229a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 4239a1de308cea2d160778fd977825f10a07b49d738Adam Powell 4249a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 425705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell * Compare the device address of a display and a route. 426705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell * Nulls/no device address will match another null/no address. 427705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell */ 428705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell static boolean matchesDeviceAddress(WifiDisplay display, RouteInfo info) { 429705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell final boolean routeHasAddress = info != null && info.mDeviceAddress != null; 430705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell if (display == null && !routeHasAddress) { 431705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell return true; 432705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 433705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 434705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell if (display != null && routeHasAddress) { 435705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell return display.getDeviceAddress().equals(info.mDeviceAddress); 436705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 437705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell return false; 438705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 439705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 440705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell /** 4419a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Add an app-specified route for media to the MediaRouter. 4429a1de308cea2d160778fd977825f10a07b49d738Adam Powell * App-specified route definitions are created using {@link #createUserRoute(RouteCategory)} 4439a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 4449a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param info Definition of the route to add 4459a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @see #createUserRoute() 4469a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @see #removeUserRoute(UserRouteInfo) 4479a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 4489a1de308cea2d160778fd977825f10a07b49d738Adam Powell public void addUserRoute(UserRouteInfo info) { 4492ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell addRouteStatic(info); 4509a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 4519a1de308cea2d160778fd977825f10a07b49d738Adam Powell 452d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell /** 453d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell * @hide Framework use only 454d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell */ 455d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell public void addRouteInt(RouteInfo info) { 4562ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell addRouteStatic(info); 457d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell } 458d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell 4592ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell static void addRouteStatic(RouteInfo info) { 4609a1de308cea2d160778fd977825f10a07b49d738Adam Powell final RouteCategory cat = info.getCategory(); 461b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn if (!sStatic.mCategories.contains(cat)) { 462b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn sStatic.mCategories.add(cat); 4639a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 464d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell if (cat.isGroupable() && !(info instanceof RouteGroup)) { 4659a1de308cea2d160778fd977825f10a07b49d738Adam Powell // Enforce that any added route in a groupable category must be in a group. 4669a1de308cea2d160778fd977825f10a07b49d738Adam Powell final RouteGroup group = new RouteGroup(info.getCategory()); 467dbbfa702a09f6d2d36dee1b552442d04a4673f89Adam Powell group.mSupportedTypes = info.mSupportedTypes; 468b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn sStatic.mRoutes.add(group); 469d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell dispatchRouteAdded(group); 470b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell group.addRoute(info); 471d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell 4729a1de308cea2d160778fd977825f10a07b49d738Adam Powell info = group; 473d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell } else { 474b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn sStatic.mRoutes.add(info); 475d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell dispatchRouteAdded(info); 4769a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 4779a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 4789a1de308cea2d160778fd977825f10a07b49d738Adam Powell 4799a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 4809a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Remove an app-specified route for media from the MediaRouter. 4819a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 4829a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param info Definition of the route to remove 4839a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @see #addUserRoute(UserRouteInfo) 4849a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 4859a1de308cea2d160778fd977825f10a07b49d738Adam Powell public void removeUserRoute(UserRouteInfo info) { 4869a1de308cea2d160778fd977825f10a07b49d738Adam Powell removeRoute(info); 4879a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 4889a1de308cea2d160778fd977825f10a07b49d738Adam Powell 489690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell /** 490690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell * Remove all app-specified routes from the MediaRouter. 491690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell * 492690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell * @see #removeUserRoute(UserRouteInfo) 493690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell */ 494690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell public void clearUserRoutes() { 495b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn for (int i = 0; i < sStatic.mRoutes.size(); i++) { 496b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn final RouteInfo info = sStatic.mRoutes.get(i); 497d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell // TODO Right now, RouteGroups only ever contain user routes. 498d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell // The code below will need to change if this assumption does. 499d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell if (info instanceof UserRouteInfo || info instanceof RouteGroup) { 500690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell removeRouteAt(i); 501690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell i--; 502690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell } 503690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell } 504690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell } 505690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell 506d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell /** 507d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell * @hide internal use only 508d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell */ 509d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell public void removeRouteInt(RouteInfo info) { 510d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell removeRoute(info); 511d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell } 512d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell 513b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn static void removeRoute(RouteInfo info) { 514b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn if (sStatic.mRoutes.remove(info)) { 5159a1de308cea2d160778fd977825f10a07b49d738Adam Powell final RouteCategory removingCat = info.getCategory(); 516b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn final int count = sStatic.mRoutes.size(); 5179a1de308cea2d160778fd977825f10a07b49d738Adam Powell boolean found = false; 5189a1de308cea2d160778fd977825f10a07b49d738Adam Powell for (int i = 0; i < count; i++) { 519b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn final RouteCategory cat = sStatic.mRoutes.get(i).getCategory(); 5209a1de308cea2d160778fd977825f10a07b49d738Adam Powell if (removingCat == cat) { 5219a1de308cea2d160778fd977825f10a07b49d738Adam Powell found = true; 5229a1de308cea2d160778fd977825f10a07b49d738Adam Powell break; 5239a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 5249a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 525d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell if (info == sStatic.mSelectedRoute) { 526d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell // Removing the currently selected route? Select the default before we remove it. 527d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell // TODO: Be smarter about the route types here; this selects for all valid. 528705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell selectRouteStatic(ROUTE_TYPE_LIVE_AUDIO | ROUTE_TYPE_USER, sStatic.mDefaultAudioVideo); 529d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell } 5309a1de308cea2d160778fd977825f10a07b49d738Adam Powell if (!found) { 531b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn sStatic.mCategories.remove(removingCat); 5329a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 5339a1de308cea2d160778fd977825f10a07b49d738Adam Powell dispatchRouteRemoved(info); 5349a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 5359a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 5369a1de308cea2d160778fd977825f10a07b49d738Adam Powell 537690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell void removeRouteAt(int routeIndex) { 538b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn if (routeIndex >= 0 && routeIndex < sStatic.mRoutes.size()) { 539b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn final RouteInfo info = sStatic.mRoutes.remove(routeIndex); 540690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell final RouteCategory removingCat = info.getCategory(); 541b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn final int count = sStatic.mRoutes.size(); 542690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell boolean found = false; 543690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell for (int i = 0; i < count; i++) { 544b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn final RouteCategory cat = sStatic.mRoutes.get(i).getCategory(); 545690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell if (removingCat == cat) { 546690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell found = true; 547690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell break; 548690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell } 549690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell } 550d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell if (info == sStatic.mSelectedRoute) { 551d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell // Removing the currently selected route? Select the default before we remove it. 552d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell // TODO: Be smarter about the route types here; this selects for all valid. 553705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell selectRouteStatic(ROUTE_TYPE_LIVE_AUDIO | ROUTE_TYPE_LIVE_VIDEO | ROUTE_TYPE_USER, 554705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell sStatic.mDefaultAudioVideo); 555d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell } 556690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell if (!found) { 557b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn sStatic.mCategories.remove(removingCat); 558690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell } 559690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell dispatchRouteRemoved(info); 560690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell } 561690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell } 562690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell 5639a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 5649a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Return the number of {@link MediaRouter.RouteCategory categories} currently 5659a1de308cea2d160778fd977825f10a07b49d738Adam Powell * represented by routes known to this MediaRouter. 5669a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 5679a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @return the number of unique categories represented by this MediaRouter's known routes 5689a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 5699a1de308cea2d160778fd977825f10a07b49d738Adam Powell public int getCategoryCount() { 570b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn return sStatic.mCategories.size(); 5719a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 5729a1de308cea2d160778fd977825f10a07b49d738Adam Powell 5739a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 5749a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Return the {@link MediaRouter.RouteCategory category} at the given index. 5759a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Valid indices are in the range [0-getCategoryCount). 5769a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 5779a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param index which category to return 5789a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @return the category at index 5799a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 5809a1de308cea2d160778fd977825f10a07b49d738Adam Powell public RouteCategory getCategoryAt(int index) { 581b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn return sStatic.mCategories.get(index); 5829a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 5839a1de308cea2d160778fd977825f10a07b49d738Adam Powell 5849a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 5859a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Return the number of {@link MediaRouter.RouteInfo routes} currently known 5869a1de308cea2d160778fd977825f10a07b49d738Adam Powell * to this MediaRouter. 5879a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 5889a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @return the number of routes tracked by this router 5899a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 5909a1de308cea2d160778fd977825f10a07b49d738Adam Powell public int getRouteCount() { 591b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn return sStatic.mRoutes.size(); 5929a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 5939a1de308cea2d160778fd977825f10a07b49d738Adam Powell 5949a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 5959a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Return the route at the specified index. 5969a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 5979a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param index index of the route to return 5989a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @return the route at index 5999a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 6009a1de308cea2d160778fd977825f10a07b49d738Adam Powell public RouteInfo getRouteAt(int index) { 601b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn return sStatic.mRoutes.get(index); 602b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn } 603b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn 604b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn static int getRouteCountStatic() { 605b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn return sStatic.mRoutes.size(); 606b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn } 607b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn 608b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn static RouteInfo getRouteAtStatic(int index) { 609b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn return sStatic.mRoutes.get(index); 6109a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 6119a1de308cea2d160778fd977825f10a07b49d738Adam Powell 6129a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 6139a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Create a new user route that may be modified and registered for use by the application. 6149a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 6159a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param category The category the new route will belong to 6169a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @return A new UserRouteInfo for use by the application 6179a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 6189a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @see #addUserRoute(UserRouteInfo) 6199a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @see #removeUserRoute(UserRouteInfo) 6209a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @see #createRouteCategory(CharSequence) 6219a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 6229a1de308cea2d160778fd977825f10a07b49d738Adam Powell public UserRouteInfo createUserRoute(RouteCategory category) { 6239a1de308cea2d160778fd977825f10a07b49d738Adam Powell return new UserRouteInfo(category); 6249a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 6259a1de308cea2d160778fd977825f10a07b49d738Adam Powell 6269a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 6279a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Create a new route category. Each route must belong to a category. 6289a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 6299a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param name Name of the new category 6309a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param isGroupable true if routes in this category may be grouped with one another 6319a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @return the new RouteCategory 6329a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 6339a1de308cea2d160778fd977825f10a07b49d738Adam Powell public RouteCategory createRouteCategory(CharSequence name, boolean isGroupable) { 6349a1de308cea2d160778fd977825f10a07b49d738Adam Powell return new RouteCategory(name, ROUTE_TYPE_USER, isGroupable); 6359a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 6360d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell 6370d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell /** 6380d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * Create a new route category. Each route must belong to a category. 6390d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * 6400d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * @param nameResId Resource ID of the name of the new category 6410d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * @param isGroupable true if routes in this category may be grouped with one another 6420d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * @return the new RouteCategory 6430d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell */ 6440d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public RouteCategory createRouteCategory(int nameResId, boolean isGroupable) { 6450d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell return new RouteCategory(nameResId, ROUTE_TYPE_USER, isGroupable); 6460d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell } 6479a1de308cea2d160778fd977825f10a07b49d738Adam Powell 648b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn static void updateRoute(final RouteInfo info) { 6499a1de308cea2d160778fd977825f10a07b49d738Adam Powell dispatchRouteChanged(info); 6509a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 6519a1de308cea2d160778fd977825f10a07b49d738Adam Powell 652b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn static void dispatchRouteSelected(int type, RouteInfo info) { 65339d5c6172503620ac3761148adac5fd7fa20d02dAdam Powell for (CallbackInfo cbi : sStatic.mCallbacks) { 6549a1de308cea2d160778fd977825f10a07b49d738Adam Powell if ((cbi.type & type) != 0) { 655b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn cbi.cb.onRouteSelected(cbi.router, type, info); 6569a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 6579a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 6589a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 6599a1de308cea2d160778fd977825f10a07b49d738Adam Powell 660b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn static void dispatchRouteUnselected(int type, RouteInfo info) { 66139d5c6172503620ac3761148adac5fd7fa20d02dAdam Powell for (CallbackInfo cbi : sStatic.mCallbacks) { 6629a1de308cea2d160778fd977825f10a07b49d738Adam Powell if ((cbi.type & type) != 0) { 663b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn cbi.cb.onRouteUnselected(cbi.router, type, info); 6649a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 6659a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 6669a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 6679a1de308cea2d160778fd977825f10a07b49d738Adam Powell 668b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn static void dispatchRouteChanged(RouteInfo info) { 66939d5c6172503620ac3761148adac5fd7fa20d02dAdam Powell for (CallbackInfo cbi : sStatic.mCallbacks) { 6709a1de308cea2d160778fd977825f10a07b49d738Adam Powell if ((cbi.type & info.mSupportedTypes) != 0) { 671b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn cbi.cb.onRouteChanged(cbi.router, info); 6729a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 6739a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 6749a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 6759a1de308cea2d160778fd977825f10a07b49d738Adam Powell 676b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn static void dispatchRouteAdded(RouteInfo info) { 67739d5c6172503620ac3761148adac5fd7fa20d02dAdam Powell for (CallbackInfo cbi : sStatic.mCallbacks) { 6789a1de308cea2d160778fd977825f10a07b49d738Adam Powell if ((cbi.type & info.mSupportedTypes) != 0) { 679b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn cbi.cb.onRouteAdded(cbi.router, info); 6809a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 6819a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 6829a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 6839a1de308cea2d160778fd977825f10a07b49d738Adam Powell 684b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn static void dispatchRouteRemoved(RouteInfo info) { 68539d5c6172503620ac3761148adac5fd7fa20d02dAdam Powell for (CallbackInfo cbi : sStatic.mCallbacks) { 6869a1de308cea2d160778fd977825f10a07b49d738Adam Powell if ((cbi.type & info.mSupportedTypes) != 0) { 687b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn cbi.cb.onRouteRemoved(cbi.router, info); 6889a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 6899a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 6909a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 6919a1de308cea2d160778fd977825f10a07b49d738Adam Powell 692b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn static void dispatchRouteGrouped(RouteInfo info, RouteGroup group, int index) { 69339d5c6172503620ac3761148adac5fd7fa20d02dAdam Powell for (CallbackInfo cbi : sStatic.mCallbacks) { 694d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell if ((cbi.type & group.mSupportedTypes) != 0) { 695b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn cbi.cb.onRouteGrouped(cbi.router, info, group, index); 696d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell } 697d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell } 698d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell } 699d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell 700b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn static void dispatchRouteUngrouped(RouteInfo info, RouteGroup group) { 70139d5c6172503620ac3761148adac5fd7fa20d02dAdam Powell for (CallbackInfo cbi : sStatic.mCallbacks) { 702d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell if ((cbi.type & group.mSupportedTypes) != 0) { 703b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn cbi.cb.onRouteUngrouped(cbi.router, info, group); 7049a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 7059a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 7069a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 7079a1de308cea2d160778fd977825f10a07b49d738Adam Powell 7088e37a85bf3dc39519942698dc90a3951306b934bAdam Powell static void dispatchRouteVolumeChanged(RouteInfo info) { 7098e37a85bf3dc39519942698dc90a3951306b934bAdam Powell for (CallbackInfo cbi : sStatic.mCallbacks) { 7108e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if ((cbi.type & info.mSupportedTypes) != 0) { 7118e37a85bf3dc39519942698dc90a3951306b934bAdam Powell cbi.cb.onRouteVolumeChanged(cbi.router, info); 7128e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 7138e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 7148e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 7158e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 71692130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown static void dispatchRoutePresentationDisplayChanged(RouteInfo info) { 71792130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown for (CallbackInfo cbi : sStatic.mCallbacks) { 71892130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown if ((cbi.type & info.mSupportedTypes) != 0) { 71992130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown cbi.cb.onRoutePresentationDisplayChanged(cbi.router, info); 72092130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown } 72192130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown } 72292130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown } 72392130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown 7248e37a85bf3dc39519942698dc90a3951306b934bAdam Powell static void systemVolumeChanged(int newValue) { 7258e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final RouteInfo selectedRoute = sStatic.mSelectedRoute; 7268e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (selectedRoute == null) return; 7278e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 7288e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (selectedRoute == sStatic.mBluetoothA2dpRoute || 729705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell selectedRoute == sStatic.mDefaultAudioVideo) { 7308e37a85bf3dc39519942698dc90a3951306b934bAdam Powell dispatchRouteVolumeChanged(selectedRoute); 7318e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } else if (sStatic.mBluetoothA2dpRoute != null) { 7328e37a85bf3dc39519942698dc90a3951306b934bAdam Powell try { 7338e37a85bf3dc39519942698dc90a3951306b934bAdam Powell dispatchRouteVolumeChanged(sStatic.mAudioService.isBluetoothA2dpOn() ? 734705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell sStatic.mBluetoothA2dpRoute : sStatic.mDefaultAudioVideo); 7358e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } catch (RemoteException e) { 7368e37a85bf3dc39519942698dc90a3951306b934bAdam Powell Log.e(TAG, "Error checking Bluetooth A2DP state to report volume change", e); 7378e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 7388e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } else { 739705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell dispatchRouteVolumeChanged(sStatic.mDefaultAudioVideo); 740705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 741705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 742705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 743705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell static void updateWifiDisplayStatus(WifiDisplayStatus newStatus) { 744705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell final WifiDisplayStatus oldStatus = sStatic.mLastKnownWifiDisplayStatus; 745705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 746705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell // TODO Naive implementation. Make this smarter later. 747b072a9686c29bfbc05b732076a4e89bcca8db08aAdam Powell boolean wantScan = false; 748b072a9686c29bfbc05b732076a4e89bcca8db08aAdam Powell boolean blockScan = false; 749705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell WifiDisplay[] oldDisplays = oldStatus != null ? 750705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell oldStatus.getRememberedDisplays() : new WifiDisplay[0]; 751705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell WifiDisplay[] newDisplays = newStatus.getRememberedDisplays(); 752705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell WifiDisplay[] availableDisplays = newStatus.getAvailableDisplays(); 7532ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell WifiDisplay activeDisplay = newStatus.getActiveDisplay(); 754705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 755705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell for (int i = 0; i < newDisplays.length; i++) { 756705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell final WifiDisplay d = newDisplays[i]; 757705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell final WifiDisplay oldRemembered = findMatchingDisplay(d, oldDisplays); 758705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell if (oldRemembered == null) { 75911b999d0aaca72a33526795b6849b473cc3dd569Adam Powell addRouteStatic(makeWifiDisplayRoute(d, 76011b999d0aaca72a33526795b6849b473cc3dd569Adam Powell findMatchingDisplay(d, availableDisplays) != null)); 761b072a9686c29bfbc05b732076a4e89bcca8db08aAdam Powell wantScan = true; 762705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } else { 763705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell final boolean available = findMatchingDisplay(d, availableDisplays) != null; 764705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell final RouteInfo route = findWifiDisplayRoute(d); 765705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell updateWifiDisplayRoute(route, d, available, newStatus); 766705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 7672ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell if (d.equals(activeDisplay)) { 7682ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell final RouteInfo activeRoute = findWifiDisplayRoute(d); 7692ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell if (activeRoute != null) { 7702ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell selectRouteStatic(activeRoute.getSupportedTypes(), activeRoute); 771b072a9686c29bfbc05b732076a4e89bcca8db08aAdam Powell 772b072a9686c29bfbc05b732076a4e89bcca8db08aAdam Powell // Don't scan if we're already connected to a wifi display, 773b072a9686c29bfbc05b732076a4e89bcca8db08aAdam Powell // the scanning process can cause a hiccup with some configurations. 774b072a9686c29bfbc05b732076a4e89bcca8db08aAdam Powell blockScan = true; 7752ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell } 7762ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell } 777705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 778705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell for (int i = 0; i < oldDisplays.length; i++) { 779705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell final WifiDisplay d = oldDisplays[i]; 780705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell final WifiDisplay newDisplay = findMatchingDisplay(d, newDisplays); 781705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell if (newDisplay == null) { 782705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell removeRoute(findWifiDisplayRoute(d)); 783705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 784705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 785705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 786b072a9686c29bfbc05b732076a4e89bcca8db08aAdam Powell if (wantScan && !blockScan) { 787705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell sStatic.mDisplayService.scanWifiDisplays(); 788705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 789705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 790705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell sStatic.mLastKnownWifiDisplayStatus = newStatus; 791705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 792705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 79311b999d0aaca72a33526795b6849b473cc3dd569Adam Powell static RouteInfo makeWifiDisplayRoute(WifiDisplay display, boolean available) { 794705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell final RouteInfo newRoute = new RouteInfo(sStatic.mSystemCategory); 795705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell newRoute.mDeviceAddress = display.getDeviceAddress(); 796705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell newRoute.mSupportedTypes = ROUTE_TYPE_LIVE_AUDIO | ROUTE_TYPE_LIVE_VIDEO; 797705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell newRoute.mVolumeHandling = RouteInfo.PLAYBACK_VOLUME_FIXED; 798705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell newRoute.mPlaybackType = RouteInfo.PLAYBACK_TYPE_REMOTE; 79911b999d0aaca72a33526795b6849b473cc3dd569Adam Powell 80011b999d0aaca72a33526795b6849b473cc3dd569Adam Powell newRoute.setStatusCode(available ? 80111b999d0aaca72a33526795b6849b473cc3dd569Adam Powell RouteInfo.STATUS_AVAILABLE : RouteInfo.STATUS_CONNECTING); 80211b999d0aaca72a33526795b6849b473cc3dd569Adam Powell newRoute.mEnabled = available; 803705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 8042444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown newRoute.mName = display.getFriendlyDisplayName(); 80592130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown 80692130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown newRoute.mPresentationDisplay = choosePresentationDisplayForRoute(newRoute, 80792130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown sStatic.getAllPresentationDisplays()); 808705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell return newRoute; 809705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 810705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 811705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell private static void updateWifiDisplayRoute(RouteInfo route, WifiDisplay display, 812705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell boolean available, WifiDisplayStatus wifiDisplayStatus) { 813705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell final boolean isScanning = 814705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell wifiDisplayStatus.getScanState() == WifiDisplayStatus.SCAN_STATE_SCANNING; 815705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 816705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell boolean changed = false; 817705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell int newStatus = RouteInfo.STATUS_NONE; 818705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 819705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell if (available) { 820705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell newStatus = isScanning ? RouteInfo.STATUS_SCANNING : RouteInfo.STATUS_AVAILABLE; 821705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } else { 822705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell newStatus = RouteInfo.STATUS_NOT_AVAILABLE; 823705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 824705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 825705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell if (display.equals(wifiDisplayStatus.getActiveDisplay())) { 826705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell final int activeState = wifiDisplayStatus.getActiveDisplayState(); 827705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell switch (activeState) { 828705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell case WifiDisplayStatus.DISPLAY_STATE_CONNECTED: 829705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell newStatus = RouteInfo.STATUS_NONE; 830705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell break; 831705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell case WifiDisplayStatus.DISPLAY_STATE_CONNECTING: 832705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell newStatus = RouteInfo.STATUS_CONNECTING; 833705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell break; 834705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell case WifiDisplayStatus.DISPLAY_STATE_NOT_CONNECTED: 835705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell Log.e(TAG, "Active display is not connected!"); 836705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell break; 837705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 838705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 839705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 8402444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown final String newName = display.getFriendlyDisplayName(); 8412444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown if (!route.getName().equals(newName)) { 842705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell route.mName = newName; 843705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell changed = true; 844705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 845705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 846705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell changed |= route.mEnabled != available; 847705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell route.mEnabled = available; 848705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 849705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell changed |= route.setStatusCode(newStatus); 850705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 851705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell if (changed) { 852705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell dispatchRouteChanged(route); 853705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 854705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 855705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell if (!available && route == sStatic.mSelectedRoute) { 856705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell // Oops, no longer available. Reselect the default. 857705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell final RouteInfo defaultRoute = sStatic.mDefaultAudioVideo; 858705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell selectRouteStatic(defaultRoute.getSupportedTypes(), defaultRoute); 859705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 860705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 861705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 8622444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown private static WifiDisplay findMatchingDisplay(WifiDisplay d, WifiDisplay[] displays) { 863705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell for (int i = 0; i < displays.length; i++) { 8642444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown final WifiDisplay other = displays[i]; 8652444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown if (d.getDeviceAddress().equals(other.getDeviceAddress())) { 8662444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown return other; 867705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 868705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 869705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell return null; 870705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 871705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 872705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell private static RouteInfo findWifiDisplayRoute(WifiDisplay d) { 873705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell final int count = sStatic.mRoutes.size(); 874705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell for (int i = 0; i < count; i++) { 875705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell final RouteInfo info = sStatic.mRoutes.get(i); 876705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell if (d.getDeviceAddress().equals(info.mDeviceAddress)) { 877705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell return info; 878705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 879705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 880705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell return null; 8818e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 8828e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 88392130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown private static Display choosePresentationDisplayForRoute(RouteInfo route, Display[] displays) { 88492130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown if ((route.mSupportedTypes & ROUTE_TYPE_LIVE_VIDEO) != 0) { 88592130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown if (route.mDeviceAddress != null) { 88692130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown // Find the indicated Wifi display by its address. 88792130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown for (Display display : displays) { 88892130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown if (display.getType() == Display.TYPE_WIFI 88992130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown && route.mDeviceAddress.equals(display.getAddress())) { 89092130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown return display; 89192130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown } 89292130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown } 89392130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown return null; 89492130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown } 89592130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown 89692130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown if (route == sStatic.mDefaultAudioVideo && displays.length > 0) { 89792130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown // Choose the first presentation display from the list. 89892130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown return displays[0]; 89992130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown } 90092130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown } 90192130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown return null; 90292130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown } 90392130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown 9049a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 9059a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Information about a media route. 9069a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 907b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn public static class RouteInfo { 9089a1de308cea2d160778fd977825f10a07b49d738Adam Powell CharSequence mName; 9090d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell int mNameResId; 9109a1de308cea2d160778fd977825f10a07b49d738Adam Powell private CharSequence mStatus; 9119a1de308cea2d160778fd977825f10a07b49d738Adam Powell int mSupportedTypes; 9129a1de308cea2d160778fd977825f10a07b49d738Adam Powell RouteGroup mGroup; 9139a1de308cea2d160778fd977825f10a07b49d738Adam Powell final RouteCategory mCategory; 914ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell Drawable mIcon; 9151357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi // playback information 9161357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi int mPlaybackType = PLAYBACK_TYPE_LOCAL; 9171357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi int mVolumeMax = RemoteControlClient.DEFAULT_PLAYBACK_VOLUME; 9181357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi int mVolume = RemoteControlClient.DEFAULT_PLAYBACK_VOLUME; 9191357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi int mVolumeHandling = RemoteControlClient.DEFAULT_PLAYBACK_VOLUME_HANDLING; 9201357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi int mPlaybackStream = AudioManager.STREAM_MUSIC; 9211357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi VolumeCallbackInfo mVcb; 92292130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown Display mPresentationDisplay; 9239a1de308cea2d160778fd977825f10a07b49d738Adam Powell 924705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell String mDeviceAddress; 925705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell boolean mEnabled = true; 926705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 927705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell // A predetermined connection status that can override mStatus 928705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell private int mStatusCode; 929705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 9302ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell /** @hide */ public static final int STATUS_NONE = 0; 9312ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell /** @hide */ public static final int STATUS_SCANNING = 1; 9322ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell /** @hide */ public static final int STATUS_CONNECTING = 2; 9332ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell /** @hide */ public static final int STATUS_AVAILABLE = 3; 9342ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell /** @hide */ public static final int STATUS_NOT_AVAILABLE = 4; 935705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 936b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell private Object mTag; 937b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell 9381357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 9391357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * The default playback type, "local", indicating the presentation of the media is happening 9401357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * on the same device (e.g. a phone, a tablet) as where it is controlled from. 9411357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @see #setPlaybackType(int) 9421357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 9431357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public final static int PLAYBACK_TYPE_LOCAL = 0; 9441357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 9451357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * A playback type indicating the presentation of the media is happening on 9461357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * a different device (i.e. the remote device) than where it is controlled from. 9471357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @see #setPlaybackType(int) 9481357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 9491357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public final static int PLAYBACK_TYPE_REMOTE = 1; 9501357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 9511357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * Playback information indicating the playback volume is fixed, i.e. it cannot be 9521357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * controlled from this object. An example of fixed playback volume is a remote player, 9531357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * playing over HDMI where the user prefers to control the volume on the HDMI sink, rather 9541357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * than attenuate at the source. 9551357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @see #setVolumeHandling(int) 9561357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 9571357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public final static int PLAYBACK_VOLUME_FIXED = 0; 9581357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 9591357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * Playback information indicating the playback volume is variable and can be controlled 9601357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * from this object. 9611357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 9621357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public final static int PLAYBACK_VOLUME_VARIABLE = 1; 9631357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 9649a1de308cea2d160778fd977825f10a07b49d738Adam Powell RouteInfo(RouteCategory category) { 9659a1de308cea2d160778fd977825f10a07b49d738Adam Powell mCategory = category; 9669a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 9679a1de308cea2d160778fd977825f10a07b49d738Adam Powell 9689a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 9699a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @return The user-friendly name of a media route. This is the string presented 9709a1de308cea2d160778fd977825f10a07b49d738Adam Powell * to users who may select this as the active route. 9719a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 9729a1de308cea2d160778fd977825f10a07b49d738Adam Powell public CharSequence getName() { 9730d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell return getName(sStatic.mResources); 9740d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell } 9750d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell 9760d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell /** 9770d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * Return the properly localized/resource selected name of this route. 9780d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * 9790d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * @param context Context used to resolve the correct configuration to load 9800d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * @return The user-friendly name of the media route. This is the string presented 9810d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * to users who may select this as the active route. 9820d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell */ 9830d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public CharSequence getName(Context context) { 9840d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell return getName(context.getResources()); 9850d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell } 9860d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell 9870d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell CharSequence getName(Resources res) { 9880d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell if (mNameResId != 0) { 9890d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell return mName = res.getText(mNameResId); 9900d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell } 9919a1de308cea2d160778fd977825f10a07b49d738Adam Powell return mName; 9929a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 9939a1de308cea2d160778fd977825f10a07b49d738Adam Powell 9949a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 9959a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @return The user-friendly status for a media route. This may include a description 9969a1de308cea2d160778fd977825f10a07b49d738Adam Powell * of the currently playing media, if available. 9979a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 9989a1de308cea2d160778fd977825f10a07b49d738Adam Powell public CharSequence getStatus() { 9999a1de308cea2d160778fd977825f10a07b49d738Adam Powell return mStatus; 10009a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 10019a1de308cea2d160778fd977825f10a07b49d738Adam Powell 10029a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 1003705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell * Set this route's status by predetermined status code. If the caller 1004705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell * should dispatch a route changed event this call will return true; 1005705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell */ 1006705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell boolean setStatusCode(int statusCode) { 1007705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell if (statusCode != mStatusCode) { 1008705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell mStatusCode = statusCode; 1009705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell int resId = 0; 1010705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell switch (statusCode) { 1011705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell case STATUS_SCANNING: 1012705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell resId = com.android.internal.R.string.media_route_status_scanning; 1013705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell break; 1014705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell case STATUS_CONNECTING: 1015705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell resId = com.android.internal.R.string.media_route_status_connecting; 1016705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell break; 1017705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell case STATUS_AVAILABLE: 1018705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell resId = com.android.internal.R.string.media_route_status_available; 1019705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell break; 1020705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell case STATUS_NOT_AVAILABLE: 1021705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell resId = com.android.internal.R.string.media_route_status_not_available; 1022705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell break; 1023705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1024705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell mStatus = resId != 0 ? sStatic.mResources.getText(resId) : null; 1025705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell return true; 1026705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1027705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell return false; 1028705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1029705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 1030705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell /** 10312ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell * @hide 10322ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell */ 10332ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell public int getStatusCode() { 10342ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell return mStatusCode; 10352ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell } 10362ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell 10372ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell /** 10389a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @return A media type flag set describing which types this route supports. 10399a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 10409a1de308cea2d160778fd977825f10a07b49d738Adam Powell public int getSupportedTypes() { 10419a1de308cea2d160778fd977825f10a07b49d738Adam Powell return mSupportedTypes; 10429a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 10439a1de308cea2d160778fd977825f10a07b49d738Adam Powell 10449a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 10459a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @return The group that this route belongs to. 10469a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 10479a1de308cea2d160778fd977825f10a07b49d738Adam Powell public RouteGroup getGroup() { 10489a1de308cea2d160778fd977825f10a07b49d738Adam Powell return mGroup; 10499a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 10509a1de308cea2d160778fd977825f10a07b49d738Adam Powell 10519a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 10529a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @return the category this route belongs to. 10539a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 10549a1de308cea2d160778fd977825f10a07b49d738Adam Powell public RouteCategory getCategory() { 10559a1de308cea2d160778fd977825f10a07b49d738Adam Powell return mCategory; 10569a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 10579a1de308cea2d160778fd977825f10a07b49d738Adam Powell 1058ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell /** 1059ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * Get the icon representing this route. 1060ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * This icon will be used in picker UIs if available. 1061ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * 1062ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * @return the icon representing this route or null if no icon is available 1063ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell */ 1064ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell public Drawable getIconDrawable() { 1065ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell return mIcon; 1066ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell } 1067ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell 1068b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell /** 1069b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell * Set an application-specific tag object for this route. 1070b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell * The application may use this to store arbitrary data associated with the 1071b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell * route for internal tracking. 1072b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell * 1073b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell * <p>Note that the lifespan of a route may be well past the lifespan of 1074b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell * an Activity or other Context; take care that objects you store here 1075b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell * will not keep more data in memory alive than you intend.</p> 1076b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell * 1077b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell * @param tag Arbitrary, app-specific data for this route to hold for later use 1078b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell */ 1079b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell public void setTag(Object tag) { 1080b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell mTag = tag; 1081130b4572d1f3df702e5b296a655d15a41f6d4c66Adam Powell routeUpdated(); 1082b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell } 1083b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell 1084b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell /** 1085b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell * @return The tag object previously set by the application 1086b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell * @see #setTag(Object) 1087b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell */ 1088b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell public Object getTag() { 1089b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell return mTag; 1090b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell } 1091b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell 10921357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 10931357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @return the type of playback associated with this route 10941357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @see UserRouteInfo#setPlaybackType(int) 10951357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 10961357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public int getPlaybackType() { 10971357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi return mPlaybackType; 10981357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 10991357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 11001357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 11011357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @return the stream over which the playback associated with this route is performed 11021357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @see UserRouteInfo#setPlaybackStream(int) 11031357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 11041357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public int getPlaybackStream() { 11051357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi return mPlaybackStream; 11061357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 11071357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 11081357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 11098e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * Return the current volume for this route. Depending on the route, this may only 11108e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * be valid if the route is currently selected. 11118e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * 11121357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @return the volume at which the playback associated with this route is performed 11131357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @see UserRouteInfo#setVolume(int) 11141357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 11151357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public int getVolume() { 11161357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi if (mPlaybackType == PLAYBACK_TYPE_LOCAL) { 11171357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi int vol = 0; 11181357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi try { 11191357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi vol = sStatic.mAudioService.getStreamVolume(mPlaybackStream); 11201357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } catch (RemoteException e) { 11211357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi Log.e(TAG, "Error getting local stream volume", e); 11221357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 11231357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi return vol; 11241357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } else { 11251357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi return mVolume; 11261357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 11271357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 11281357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 11291357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 11308e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * Request a volume change for this route. 11318e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * @param volume value between 0 and getVolumeMax 11328e37a85bf3dc39519942698dc90a3951306b934bAdam Powell */ 11338e37a85bf3dc39519942698dc90a3951306b934bAdam Powell public void requestSetVolume(int volume) { 11348e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (mPlaybackType == PLAYBACK_TYPE_LOCAL) { 11358e37a85bf3dc39519942698dc90a3951306b934bAdam Powell try { 11368e37a85bf3dc39519942698dc90a3951306b934bAdam Powell sStatic.mAudioService.setStreamVolume(mPlaybackStream, volume, 0); 11378e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } catch (RemoteException e) { 11388e37a85bf3dc39519942698dc90a3951306b934bAdam Powell Log.e(TAG, "Error setting local stream volume", e); 11398e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 11408e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } else { 11418e37a85bf3dc39519942698dc90a3951306b934bAdam Powell Log.e(TAG, getClass().getSimpleName() + ".requestSetVolume(): " + 11428e37a85bf3dc39519942698dc90a3951306b934bAdam Powell "Non-local volume playback on system route? " + 11438e37a85bf3dc39519942698dc90a3951306b934bAdam Powell "Could not request volume change."); 11448e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 11458e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 11468e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 11478e37a85bf3dc39519942698dc90a3951306b934bAdam Powell /** 11488e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * Request an incremental volume update for this route. 11498e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * @param direction Delta to apply to the current volume 11508e37a85bf3dc39519942698dc90a3951306b934bAdam Powell */ 11518e37a85bf3dc39519942698dc90a3951306b934bAdam Powell public void requestUpdateVolume(int direction) { 11528e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (mPlaybackType == PLAYBACK_TYPE_LOCAL) { 11538e37a85bf3dc39519942698dc90a3951306b934bAdam Powell try { 11548e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final int volume = 11558e37a85bf3dc39519942698dc90a3951306b934bAdam Powell Math.max(0, Math.min(getVolume() + direction, getVolumeMax())); 11568e37a85bf3dc39519942698dc90a3951306b934bAdam Powell sStatic.mAudioService.setStreamVolume(mPlaybackStream, volume, 0); 11578e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } catch (RemoteException e) { 11588e37a85bf3dc39519942698dc90a3951306b934bAdam Powell Log.e(TAG, "Error setting local stream volume", e); 11598e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 11608e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } else { 11618e37a85bf3dc39519942698dc90a3951306b934bAdam Powell Log.e(TAG, getClass().getSimpleName() + ".requestChangeVolume(): " + 11628e37a85bf3dc39519942698dc90a3951306b934bAdam Powell "Non-local volume playback on system route? " + 11638e37a85bf3dc39519942698dc90a3951306b934bAdam Powell "Could not request volume change."); 11648e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 11658e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 11668e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 11678e37a85bf3dc39519942698dc90a3951306b934bAdam Powell /** 11681357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @return the maximum volume at which the playback associated with this route is performed 11691357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @see UserRouteInfo#setVolumeMax(int) 11701357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 11711357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public int getVolumeMax() { 11721357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi if (mPlaybackType == PLAYBACK_TYPE_LOCAL) { 11731357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi int volMax = 0; 11741357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi try { 11751357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi volMax = sStatic.mAudioService.getStreamMaxVolume(mPlaybackStream); 11761357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } catch (RemoteException e) { 11771357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi Log.e(TAG, "Error getting local stream volume", e); 11781357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 11791357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi return volMax; 11801357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } else { 11811357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi return mVolumeMax; 11821357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 11831357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 11841357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 11851357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 11861357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @return how volume is handling on the route 11871357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @see UserRouteInfo#setVolumeHandling(int) 11881357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 11891357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public int getVolumeHandling() { 11901357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi return mVolumeHandling; 11911357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 11921357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 1193705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell /** 119492130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * Gets the {@link Display} that should be used by the application to show 119592130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * a {@link android.app.Presentation} on an external display when this route is selected. 119692130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * Depending on the route, this may only be valid if the route is currently 119792130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * selected. 119892130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * <p> 119992130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * The preferred presentation display may change independently of the route 120092130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * being selected or unselected. For example, the presentation display 120192130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * of the default system route may change when an external HDMI display is connected 120292130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * or disconnected even though the route itself has not changed. 120392130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * </p><p> 120492130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * This method may return null if there is no external display associated with 120592130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * the route or if the display is not ready to show UI yet. 120692130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * </p><p> 120792130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * The application should listen for changes to the presentation display 120892130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * using the {@link Callback#onRoutePresentationDisplayChanged} callback and 120992130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * show or dismiss its {@link android.app.Presentation} accordingly when the display 121092130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * becomes available or is removed. 121192130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * </p><p> 121292130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * This method only makes sense for {@link #ROUTE_TYPE_LIVE_VIDEO live video} routes. 121392130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * </p> 121492130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * 121592130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * @return The preferred presentation display to use when this route is 121692130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * selected or null if none. 121792130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * 121892130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * @see #ROUTE_TYPE_LIVE_VIDEO 121992130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * @see android.app.Presentation 122092130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown */ 122192130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown public Display getPresentationDisplay() { 122292130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown return mPresentationDisplay; 122392130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown } 122492130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown 122592130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown /** 1226705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell * @return true if this route is enabled and may be selected 1227705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell */ 1228705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell public boolean isEnabled() { 1229705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell return mEnabled; 1230705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1231705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 12329a1de308cea2d160778fd977825f10a07b49d738Adam Powell void setStatusInt(CharSequence status) { 12339a1de308cea2d160778fd977825f10a07b49d738Adam Powell if (!status.equals(mStatus)) { 12349a1de308cea2d160778fd977825f10a07b49d738Adam Powell mStatus = status; 12359a1de308cea2d160778fd977825f10a07b49d738Adam Powell if (mGroup != null) { 12369a1de308cea2d160778fd977825f10a07b49d738Adam Powell mGroup.memberStatusChanged(this, status); 12379a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 12389a1de308cea2d160778fd977825f10a07b49d738Adam Powell routeUpdated(); 12399a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 12409a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 12419a1de308cea2d160778fd977825f10a07b49d738Adam Powell 12421357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi final IRemoteVolumeObserver.Stub mRemoteVolObserver = new IRemoteVolumeObserver.Stub() { 12431357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public void dispatchRemoteVolumeUpdate(final int direction, final int value) { 12441357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi sStatic.mHandler.post(new Runnable() { 12451357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi @Override 12461357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public void run() { 12471357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi if (mVcb != null) { 12481357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi if (direction != 0) { 12491357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi mVcb.vcb.onVolumeUpdateRequest(mVcb.route, direction); 12501357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } else { 12511357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi mVcb.vcb.onVolumeSetRequest(mVcb.route, value); 12521357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 12531357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 12541357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 12551357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi }); 12561357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 12571357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi }; 12581357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 12599a1de308cea2d160778fd977825f10a07b49d738Adam Powell void routeUpdated() { 12609a1de308cea2d160778fd977825f10a07b49d738Adam Powell updateRoute(this); 12619a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 12629a1de308cea2d160778fd977825f10a07b49d738Adam Powell 12639a1de308cea2d160778fd977825f10a07b49d738Adam Powell @Override 12649a1de308cea2d160778fd977825f10a07b49d738Adam Powell public String toString() { 1265d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell String supportedTypes = typesToString(getSupportedTypes()); 126692130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown return getClass().getSimpleName() + "{ name=" + getName() + 126792130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown ", status=" + getStatus() + 126892130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown ", category=" + getCategory() + 126992130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown ", supportedTypes=" + supportedTypes + 127092130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown ", presentationDisplay=" + mPresentationDisplay + "}"; 12719a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 12729a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 12739a1de308cea2d160778fd977825f10a07b49d738Adam Powell 12749a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 12759a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Information about a route that the application may define and modify. 12768e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * A user route defaults to {@link RouteInfo#PLAYBACK_TYPE_REMOTE} and 12778e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * {@link RouteInfo#PLAYBACK_VOLUME_FIXED}. 12789a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 12799a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @see MediaRouter.RouteInfo 12809a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 1281b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn public static class UserRouteInfo extends RouteInfo { 1282ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell RemoteControlClient mRcc; 12839a1de308cea2d160778fd977825f10a07b49d738Adam Powell 12849a1de308cea2d160778fd977825f10a07b49d738Adam Powell UserRouteInfo(RouteCategory category) { 12859a1de308cea2d160778fd977825f10a07b49d738Adam Powell super(category); 12869a1de308cea2d160778fd977825f10a07b49d738Adam Powell mSupportedTypes = ROUTE_TYPE_USER; 12878e37a85bf3dc39519942698dc90a3951306b934bAdam Powell mPlaybackType = PLAYBACK_TYPE_REMOTE; 12888e37a85bf3dc39519942698dc90a3951306b934bAdam Powell mVolumeHandling = PLAYBACK_VOLUME_FIXED; 12899a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 12909a1de308cea2d160778fd977825f10a07b49d738Adam Powell 12919a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 12929a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Set the user-visible name of this route. 12939a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param name Name to display to the user to describe this route 12949a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 12959a1de308cea2d160778fd977825f10a07b49d738Adam Powell public void setName(CharSequence name) { 12969a1de308cea2d160778fd977825f10a07b49d738Adam Powell mName = name; 12979a1de308cea2d160778fd977825f10a07b49d738Adam Powell routeUpdated(); 12989a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 12990d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell 13000d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell /** 13010d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * Set the user-visible name of this route. 13020d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * @param resId Resource ID of the name to display to the user to describe this route 13030d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell */ 13040d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public void setName(int resId) { 13050d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell mNameResId = resId; 13060d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell mName = null; 13070d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell routeUpdated(); 13080d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell } 13099a1de308cea2d160778fd977825f10a07b49d738Adam Powell 13109a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 13119a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Set the current user-visible status for this route. 13129a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param status Status to display to the user to describe what the endpoint 13139a1de308cea2d160778fd977825f10a07b49d738Adam Powell * of this route is currently doing 13149a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 13159a1de308cea2d160778fd977825f10a07b49d738Adam Powell public void setStatus(CharSequence status) { 13169a1de308cea2d160778fd977825f10a07b49d738Adam Powell setStatusInt(status); 13179a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 1318ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell 1319ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell /** 1320ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * Set the RemoteControlClient responsible for reporting playback info for this 1321ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * user route. 1322ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * 1323ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * <p>If this route manages remote playback, the data exposed by this 1324ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * RemoteControlClient will be used to reflect and update information 1325ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * such as route volume info in related UIs.</p> 1326ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * 13271357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * <p>The RemoteControlClient must have been previously registered with 13281357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * {@link AudioManager#registerRemoteControlClient(RemoteControlClient)}.</p> 13291357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * 1330ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * @param rcc RemoteControlClient associated with this route 1331ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell */ 1332ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell public void setRemoteControlClient(RemoteControlClient rcc) { 1333ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell mRcc = rcc; 13341357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi updatePlaybackInfoOnRcc(); 1335ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell } 1336ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell 1337ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell /** 13384599696591f745b3a546197d2ba7e5cfc5562484Adam Powell * Retrieve the RemoteControlClient associated with this route, if one has been set. 13394599696591f745b3a546197d2ba7e5cfc5562484Adam Powell * 13404599696591f745b3a546197d2ba7e5cfc5562484Adam Powell * @return the RemoteControlClient associated with this route 13414599696591f745b3a546197d2ba7e5cfc5562484Adam Powell * @see #setRemoteControlClient(RemoteControlClient) 13424599696591f745b3a546197d2ba7e5cfc5562484Adam Powell */ 13434599696591f745b3a546197d2ba7e5cfc5562484Adam Powell public RemoteControlClient getRemoteControlClient() { 13444599696591f745b3a546197d2ba7e5cfc5562484Adam Powell return mRcc; 13454599696591f745b3a546197d2ba7e5cfc5562484Adam Powell } 13464599696591f745b3a546197d2ba7e5cfc5562484Adam Powell 13474599696591f745b3a546197d2ba7e5cfc5562484Adam Powell /** 1348ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * Set an icon that will be used to represent this route. 1349ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * The system may use this icon in picker UIs or similar. 1350ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * 1351ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * @param icon icon drawable to use to represent this route 1352ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell */ 1353ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell public void setIconDrawable(Drawable icon) { 1354ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell mIcon = icon; 1355ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell } 1356ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell 1357ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell /** 1358ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * Set an icon that will be used to represent this route. 1359ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * The system may use this icon in picker UIs or similar. 1360ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * 136171c69897ad0a55d590698bfa399bfe99c763b9dbAdam Powell * @param resId Resource ID of an icon drawable to use to represent this route 1362ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell */ 1363ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell public void setIconResource(int resId) { 1364ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell setIconDrawable(sStatic.mResources.getDrawable(resId)); 1365ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell } 13661357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 13671357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 13681357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * Set a callback to be notified of volume update requests 13691357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @param vcb 13701357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 13711357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public void setVolumeCallback(VolumeCallback vcb) { 13721357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi mVcb = new VolumeCallbackInfo(vcb, this); 13731357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 13741357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 13751357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 13761357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * Defines whether playback associated with this route is "local" 13771357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * ({@link RouteInfo#PLAYBACK_TYPE_LOCAL}) or "remote" 13781357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * ({@link RouteInfo#PLAYBACK_TYPE_REMOTE}). 13791357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @param type 13801357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 13811357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public void setPlaybackType(int type) { 13821357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi if (mPlaybackType != type) { 13831357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi mPlaybackType = type; 13841357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi setPlaybackInfoOnRcc(RemoteControlClient.PLAYBACKINFO_PLAYBACK_TYPE, type); 13851357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 13861357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 13871357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 13881357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 13891357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * Defines whether volume for the playback associated with this route is fixed 13901357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * ({@link RouteInfo#PLAYBACK_VOLUME_FIXED}) or can modified 13911357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * ({@link RouteInfo#PLAYBACK_VOLUME_VARIABLE}). 13921357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @param volumeHandling 13931357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 13941357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public void setVolumeHandling(int volumeHandling) { 13951357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi if (mVolumeHandling != volumeHandling) { 13961357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi mVolumeHandling = volumeHandling; 13971357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi setPlaybackInfoOnRcc( 13981357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi RemoteControlClient.PLAYBACKINFO_VOLUME_HANDLING, volumeHandling); 13991357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 14001357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 14011357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 14021357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 14031357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * Defines at what volume the playback associated with this route is performed (for user 14041357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * feedback purposes). This information is only used when the playback is not local. 14051357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @param volume 14061357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 14071357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public void setVolume(int volume) { 14088e37a85bf3dc39519942698dc90a3951306b934bAdam Powell volume = Math.max(0, Math.min(volume, getVolumeMax())); 14091357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi if (mVolume != volume) { 14101357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi mVolume = volume; 14111357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi setPlaybackInfoOnRcc(RemoteControlClient.PLAYBACKINFO_VOLUME, volume); 14128e37a85bf3dc39519942698dc90a3951306b934bAdam Powell dispatchRouteVolumeChanged(this); 1413f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell if (mGroup != null) { 1414f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell mGroup.memberVolumeChanged(this); 1415f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell } 14168e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 14178e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 14188e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 14198e37a85bf3dc39519942698dc90a3951306b934bAdam Powell @Override 14208e37a85bf3dc39519942698dc90a3951306b934bAdam Powell public void requestSetVolume(int volume) { 14218e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (mVolumeHandling == PLAYBACK_VOLUME_VARIABLE) { 14228e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (mVcb == null) { 14238e37a85bf3dc39519942698dc90a3951306b934bAdam Powell Log.e(TAG, "Cannot requestSetVolume on user route - no volume callback set"); 14248e37a85bf3dc39519942698dc90a3951306b934bAdam Powell return; 14258e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 14268e37a85bf3dc39519942698dc90a3951306b934bAdam Powell mVcb.vcb.onVolumeSetRequest(this, volume); 14278e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 14288e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 14298e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 14308e37a85bf3dc39519942698dc90a3951306b934bAdam Powell @Override 14318e37a85bf3dc39519942698dc90a3951306b934bAdam Powell public void requestUpdateVolume(int direction) { 14328e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (mVolumeHandling == PLAYBACK_VOLUME_VARIABLE) { 14338e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (mVcb == null) { 14348e37a85bf3dc39519942698dc90a3951306b934bAdam Powell Log.e(TAG, "Cannot requestChangeVolume on user route - no volumec callback set"); 14358e37a85bf3dc39519942698dc90a3951306b934bAdam Powell return; 14368e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 14378e37a85bf3dc39519942698dc90a3951306b934bAdam Powell mVcb.vcb.onVolumeUpdateRequest(this, direction); 14381357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 14391357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 14401357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 14411357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 14421357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * Defines the maximum volume at which the playback associated with this route is performed 14431357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * (for user feedback purposes). This information is only used when the playback is not 14441357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * local. 14451357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @param volumeMax 14461357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 14471357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public void setVolumeMax(int volumeMax) { 14481357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi if (mVolumeMax != volumeMax) { 14491357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi mVolumeMax = volumeMax; 14501357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi setPlaybackInfoOnRcc(RemoteControlClient.PLAYBACKINFO_VOLUME_MAX, volumeMax); 14511357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 14521357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 14531357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 14541357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 14551357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * Defines over what stream type the media is presented. 14561357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @param stream 14571357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 14581357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public void setPlaybackStream(int stream) { 14591357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi if (mPlaybackStream != stream) { 14601357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi mPlaybackStream = stream; 14611357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi setPlaybackInfoOnRcc(RemoteControlClient.PLAYBACKINFO_USES_STREAM, stream); 14621357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 14631357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 14641357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 14651357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi private void updatePlaybackInfoOnRcc() { 14661357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi if ((mRcc != null) && (mRcc.getRcseId() != RemoteControlClient.RCSE_ID_UNREGISTERED)) { 14671357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi mRcc.setPlaybackInformation( 14681357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi RemoteControlClient.PLAYBACKINFO_VOLUME_MAX, mVolumeMax); 14691357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi mRcc.setPlaybackInformation( 14701357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi RemoteControlClient.PLAYBACKINFO_VOLUME, mVolume); 14711357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi mRcc.setPlaybackInformation( 14721357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi RemoteControlClient.PLAYBACKINFO_VOLUME_HANDLING, mVolumeHandling); 14731357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi mRcc.setPlaybackInformation( 14741357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi RemoteControlClient.PLAYBACKINFO_USES_STREAM, mPlaybackStream); 14751357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi mRcc.setPlaybackInformation( 14761357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi RemoteControlClient.PLAYBACKINFO_PLAYBACK_TYPE, mPlaybackType); 14771357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi // let AudioService know whom to call when remote volume needs to be updated 14781357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi try { 14791357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi sStatic.mAudioService.registerRemoteVolumeObserverForRcc( 14801357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi mRcc.getRcseId() /* rccId */, mRemoteVolObserver /* rvo */); 14811357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } catch (RemoteException e) { 14821357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi Log.e(TAG, "Error registering remote volume observer", e); 14831357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 14841357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 14851357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 14861357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 14871357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi private void setPlaybackInfoOnRcc(int what, int value) { 14881357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi if (mRcc != null) { 14891357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi mRcc.setPlaybackInformation(what, value); 14901357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 14911357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 14929a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 14939a1de308cea2d160778fd977825f10a07b49d738Adam Powell 14949a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 14959a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Information about a route that consists of multiple other routes in a group. 14969a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 1497b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn public static class RouteGroup extends RouteInfo { 14989a1de308cea2d160778fd977825f10a07b49d738Adam Powell final ArrayList<RouteInfo> mRoutes = new ArrayList<RouteInfo>(); 14999a1de308cea2d160778fd977825f10a07b49d738Adam Powell private boolean mUpdateName; 15009a1de308cea2d160778fd977825f10a07b49d738Adam Powell 15019a1de308cea2d160778fd977825f10a07b49d738Adam Powell RouteGroup(RouteCategory category) { 15029a1de308cea2d160778fd977825f10a07b49d738Adam Powell super(category); 15039a1de308cea2d160778fd977825f10a07b49d738Adam Powell mGroup = this; 15048e37a85bf3dc39519942698dc90a3951306b934bAdam Powell mVolumeHandling = PLAYBACK_VOLUME_FIXED; 15059a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 15069a1de308cea2d160778fd977825f10a07b49d738Adam Powell 15070d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell CharSequence getName(Resources res) { 15089a1de308cea2d160778fd977825f10a07b49d738Adam Powell if (mUpdateName) updateName(); 15090d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell return super.getName(res); 15109a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 15119a1de308cea2d160778fd977825f10a07b49d738Adam Powell 15129a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 15139a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Add a route to this group. The route must not currently belong to another group. 15149a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 15159a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param route route to add to this group 15169a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 15179a1de308cea2d160778fd977825f10a07b49d738Adam Powell public void addRoute(RouteInfo route) { 15189a1de308cea2d160778fd977825f10a07b49d738Adam Powell if (route.getGroup() != null) { 15199a1de308cea2d160778fd977825f10a07b49d738Adam Powell throw new IllegalStateException("Route " + route + " is already part of a group."); 15209a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 15219a1de308cea2d160778fd977825f10a07b49d738Adam Powell if (route.getCategory() != mCategory) { 15229a1de308cea2d160778fd977825f10a07b49d738Adam Powell throw new IllegalArgumentException( 15239a1de308cea2d160778fd977825f10a07b49d738Adam Powell "Route cannot be added to a group with a different category. " + 15249a1de308cea2d160778fd977825f10a07b49d738Adam Powell "(Route category=" + route.getCategory() + 15259a1de308cea2d160778fd977825f10a07b49d738Adam Powell " group category=" + mCategory + ")"); 15269a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 1527d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell final int at = mRoutes.size(); 15289a1de308cea2d160778fd977825f10a07b49d738Adam Powell mRoutes.add(route); 1529d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell route.mGroup = this; 15309a1de308cea2d160778fd977825f10a07b49d738Adam Powell mUpdateName = true; 1531f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell updateVolume(); 15329a1de308cea2d160778fd977825f10a07b49d738Adam Powell routeUpdated(); 1533f3b653a21cdffe04c94c275e69ecb56e00766e82Adam Powell dispatchRouteGrouped(route, this, at); 15349a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 15359a1de308cea2d160778fd977825f10a07b49d738Adam Powell 15369a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 15379a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Add a route to this group before the specified index. 15389a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 15399a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param route route to add 15409a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param insertAt insert the new route before this index 15419a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 15429a1de308cea2d160778fd977825f10a07b49d738Adam Powell public void addRoute(RouteInfo route, int insertAt) { 15439a1de308cea2d160778fd977825f10a07b49d738Adam Powell if (route.getGroup() != null) { 15449a1de308cea2d160778fd977825f10a07b49d738Adam Powell throw new IllegalStateException("Route " + route + " is already part of a group."); 15459a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 15469a1de308cea2d160778fd977825f10a07b49d738Adam Powell if (route.getCategory() != mCategory) { 15479a1de308cea2d160778fd977825f10a07b49d738Adam Powell throw new IllegalArgumentException( 15489a1de308cea2d160778fd977825f10a07b49d738Adam Powell "Route cannot be added to a group with a different category. " + 15499a1de308cea2d160778fd977825f10a07b49d738Adam Powell "(Route category=" + route.getCategory() + 15509a1de308cea2d160778fd977825f10a07b49d738Adam Powell " group category=" + mCategory + ")"); 15519a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 15529a1de308cea2d160778fd977825f10a07b49d738Adam Powell mRoutes.add(insertAt, route); 1553d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell route.mGroup = this; 15549a1de308cea2d160778fd977825f10a07b49d738Adam Powell mUpdateName = true; 1555f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell updateVolume(); 15569a1de308cea2d160778fd977825f10a07b49d738Adam Powell routeUpdated(); 1557f3b653a21cdffe04c94c275e69ecb56e00766e82Adam Powell dispatchRouteGrouped(route, this, insertAt); 15589a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 15599a1de308cea2d160778fd977825f10a07b49d738Adam Powell 15609a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 15619a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Remove a route from this group. 15629a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 15639a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param route route to remove 15649a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 15659a1de308cea2d160778fd977825f10a07b49d738Adam Powell public void removeRoute(RouteInfo route) { 15669a1de308cea2d160778fd977825f10a07b49d738Adam Powell if (route.getGroup() != this) { 15679a1de308cea2d160778fd977825f10a07b49d738Adam Powell throw new IllegalArgumentException("Route " + route + 15689a1de308cea2d160778fd977825f10a07b49d738Adam Powell " is not a member of this group."); 15699a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 15709a1de308cea2d160778fd977825f10a07b49d738Adam Powell mRoutes.remove(route); 1571d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell route.mGroup = null; 15729a1de308cea2d160778fd977825f10a07b49d738Adam Powell mUpdateName = true; 1573f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell updateVolume(); 1574d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell dispatchRouteUngrouped(route, this); 15759a1de308cea2d160778fd977825f10a07b49d738Adam Powell routeUpdated(); 15769a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 15779a1de308cea2d160778fd977825f10a07b49d738Adam Powell 15789a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 15799a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Remove the route at the specified index from this group. 15809a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 15819a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param index index of the route to remove 15829a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 15839a1de308cea2d160778fd977825f10a07b49d738Adam Powell public void removeRoute(int index) { 1584d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell RouteInfo route = mRoutes.remove(index); 1585d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell route.mGroup = null; 15869a1de308cea2d160778fd977825f10a07b49d738Adam Powell mUpdateName = true; 1587f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell updateVolume(); 1588d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell dispatchRouteUngrouped(route, this); 15899a1de308cea2d160778fd977825f10a07b49d738Adam Powell routeUpdated(); 15909a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 15919a1de308cea2d160778fd977825f10a07b49d738Adam Powell 1592d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell /** 1593d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @return The number of routes in this group 1594d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell */ 1595d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell public int getRouteCount() { 1596d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell return mRoutes.size(); 1597d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell } 1598d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell 1599d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell /** 1600d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * Return the route in this group at the specified index 1601d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * 1602d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param index Index to fetch 1603d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @return The route at index 1604d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell */ 1605d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell public RouteInfo getRouteAt(int index) { 1606d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell return mRoutes.get(index); 1607d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell } 1608d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell 1609ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell /** 1610ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * Set an icon that will be used to represent this group. 1611ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * The system may use this icon in picker UIs or similar. 1612ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * 1613ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * @param icon icon drawable to use to represent this group 1614ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell */ 1615ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell public void setIconDrawable(Drawable icon) { 1616ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell mIcon = icon; 1617ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell } 1618ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell 1619ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell /** 1620ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * Set an icon that will be used to represent this group. 1621ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * The system may use this icon in picker UIs or similar. 1622ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * 162371c69897ad0a55d590698bfa399bfe99c763b9dbAdam Powell * @param resId Resource ID of an icon drawable to use to represent this group 1624ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell */ 1625ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell public void setIconResource(int resId) { 1626ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell setIconDrawable(sStatic.mResources.getDrawable(resId)); 1627ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell } 1628ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell 16298e37a85bf3dc39519942698dc90a3951306b934bAdam Powell @Override 16308e37a85bf3dc39519942698dc90a3951306b934bAdam Powell public void requestSetVolume(int volume) { 16318e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final int maxVol = getVolumeMax(); 16328e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (maxVol == 0) { 16338e37a85bf3dc39519942698dc90a3951306b934bAdam Powell return; 16348e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 16358e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 16368e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final float scaledVolume = (float) volume / maxVol; 16378e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final int routeCount = getRouteCount(); 16388e37a85bf3dc39519942698dc90a3951306b934bAdam Powell for (int i = 0; i < routeCount; i++) { 16398e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final RouteInfo route = getRouteAt(i); 16408e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final int routeVol = (int) (scaledVolume * route.getVolumeMax()); 16418e37a85bf3dc39519942698dc90a3951306b934bAdam Powell route.requestSetVolume(routeVol); 16428e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 16438e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (volume != mVolume) { 16448e37a85bf3dc39519942698dc90a3951306b934bAdam Powell mVolume = volume; 16458e37a85bf3dc39519942698dc90a3951306b934bAdam Powell dispatchRouteVolumeChanged(this); 16468e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 16478e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 16488e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 16498e37a85bf3dc39519942698dc90a3951306b934bAdam Powell @Override 16508e37a85bf3dc39519942698dc90a3951306b934bAdam Powell public void requestUpdateVolume(int direction) { 16518e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final int maxVol = getVolumeMax(); 16528e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (maxVol == 0) { 16538e37a85bf3dc39519942698dc90a3951306b934bAdam Powell return; 16548e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 16558e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 16568e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final int routeCount = getRouteCount(); 1657f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell int volume = 0; 16588e37a85bf3dc39519942698dc90a3951306b934bAdam Powell for (int i = 0; i < routeCount; i++) { 16598e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final RouteInfo route = getRouteAt(i); 16608e37a85bf3dc39519942698dc90a3951306b934bAdam Powell route.requestUpdateVolume(direction); 1661f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell final int routeVol = route.getVolume(); 1662f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell if (routeVol > volume) { 1663f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell volume = routeVol; 1664f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell } 16658e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 16668e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (volume != mVolume) { 16678e37a85bf3dc39519942698dc90a3951306b934bAdam Powell mVolume = volume; 16688e37a85bf3dc39519942698dc90a3951306b934bAdam Powell dispatchRouteVolumeChanged(this); 16698e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 16708e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 16718e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 16729a1de308cea2d160778fd977825f10a07b49d738Adam Powell void memberNameChanged(RouteInfo info, CharSequence name) { 16739a1de308cea2d160778fd977825f10a07b49d738Adam Powell mUpdateName = true; 16749a1de308cea2d160778fd977825f10a07b49d738Adam Powell routeUpdated(); 16759a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 16769a1de308cea2d160778fd977825f10a07b49d738Adam Powell 16779a1de308cea2d160778fd977825f10a07b49d738Adam Powell void memberStatusChanged(RouteInfo info, CharSequence status) { 16789a1de308cea2d160778fd977825f10a07b49d738Adam Powell setStatusInt(status); 16799a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 16809a1de308cea2d160778fd977825f10a07b49d738Adam Powell 1681f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell void memberVolumeChanged(RouteInfo info) { 1682f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell updateVolume(); 1683f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell } 1684f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell 1685f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell void updateVolume() { 1686f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell // A group always represents the highest component volume value. 1687f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell final int routeCount = getRouteCount(); 1688f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell int volume = 0; 1689f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell for (int i = 0; i < routeCount; i++) { 1690f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell final int routeVol = getRouteAt(i).getVolume(); 1691f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell if (routeVol > volume) { 1692f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell volume = routeVol; 1693f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell } 1694f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell } 1695f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell if (volume != mVolume) { 1696f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell mVolume = volume; 1697f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell dispatchRouteVolumeChanged(this); 1698f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell } 1699f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell } 1700f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell 1701d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell @Override 1702d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell void routeUpdated() { 1703d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell int types = 0; 1704d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell final int count = mRoutes.size(); 1705b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell if (count == 0) { 1706b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell // Don't keep empty groups in the router. 1707b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell MediaRouter.removeRoute(this); 1708b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell return; 1709b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell } 1710b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell 17118e37a85bf3dc39519942698dc90a3951306b934bAdam Powell int maxVolume = 0; 17128e37a85bf3dc39519942698dc90a3951306b934bAdam Powell boolean isLocal = true; 17138e37a85bf3dc39519942698dc90a3951306b934bAdam Powell boolean isFixedVolume = true; 1714d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell for (int i = 0; i < count; i++) { 17158e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final RouteInfo route = mRoutes.get(i); 17168e37a85bf3dc39519942698dc90a3951306b934bAdam Powell types |= route.mSupportedTypes; 17178e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final int routeMaxVolume = route.getVolumeMax(); 17188e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (routeMaxVolume > maxVolume) { 17198e37a85bf3dc39519942698dc90a3951306b934bAdam Powell maxVolume = routeMaxVolume; 17208e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 17218e37a85bf3dc39519942698dc90a3951306b934bAdam Powell isLocal &= route.getPlaybackType() == PLAYBACK_TYPE_LOCAL; 17228e37a85bf3dc39519942698dc90a3951306b934bAdam Powell isFixedVolume &= route.getVolumeHandling() == PLAYBACK_VOLUME_FIXED; 1723d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell } 17248e37a85bf3dc39519942698dc90a3951306b934bAdam Powell mPlaybackType = isLocal ? PLAYBACK_TYPE_LOCAL : PLAYBACK_TYPE_REMOTE; 17258e37a85bf3dc39519942698dc90a3951306b934bAdam Powell mVolumeHandling = isFixedVolume ? PLAYBACK_VOLUME_FIXED : PLAYBACK_VOLUME_VARIABLE; 1726d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell mSupportedTypes = types; 17278e37a85bf3dc39519942698dc90a3951306b934bAdam Powell mVolumeMax = maxVolume; 1728d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell mIcon = count == 1 ? mRoutes.get(0).getIconDrawable() : null; 1729d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell super.routeUpdated(); 1730d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell } 1731d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell 17329a1de308cea2d160778fd977825f10a07b49d738Adam Powell void updateName() { 17339a1de308cea2d160778fd977825f10a07b49d738Adam Powell final StringBuilder sb = new StringBuilder(); 17349a1de308cea2d160778fd977825f10a07b49d738Adam Powell final int count = mRoutes.size(); 17359a1de308cea2d160778fd977825f10a07b49d738Adam Powell for (int i = 0; i < count; i++) { 17369a1de308cea2d160778fd977825f10a07b49d738Adam Powell final RouteInfo info = mRoutes.get(i); 1737b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell // TODO: There's probably a much more correct way to localize this. 17389a1de308cea2d160778fd977825f10a07b49d738Adam Powell if (i > 0) sb.append(", "); 17399a1de308cea2d160778fd977825f10a07b49d738Adam Powell sb.append(info.mName); 17409a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 17419a1de308cea2d160778fd977825f10a07b49d738Adam Powell mName = sb.toString(); 17429a1de308cea2d160778fd977825f10a07b49d738Adam Powell mUpdateName = false; 17439a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 1744d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell 1745d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell @Override 1746d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell public String toString() { 1747d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell StringBuilder sb = new StringBuilder(super.toString()); 1748d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell sb.append('['); 1749d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell final int count = mRoutes.size(); 1750d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell for (int i = 0; i < count; i++) { 1751d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell if (i > 0) sb.append(", "); 1752d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell sb.append(mRoutes.get(i)); 1753d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell } 1754d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell sb.append(']'); 1755d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell return sb.toString(); 1756d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell } 17579a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 17589a1de308cea2d160778fd977825f10a07b49d738Adam Powell 17599a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 17609a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Definition of a category of routes. All routes belong to a category. 17619a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 1762b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn public static class RouteCategory { 17639a1de308cea2d160778fd977825f10a07b49d738Adam Powell CharSequence mName; 17640d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell int mNameResId; 17659a1de308cea2d160778fd977825f10a07b49d738Adam Powell int mTypes; 17669a1de308cea2d160778fd977825f10a07b49d738Adam Powell final boolean mGroupable; 1767705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell boolean mIsSystem; 17689a1de308cea2d160778fd977825f10a07b49d738Adam Powell 17699a1de308cea2d160778fd977825f10a07b49d738Adam Powell RouteCategory(CharSequence name, int types, boolean groupable) { 17709a1de308cea2d160778fd977825f10a07b49d738Adam Powell mName = name; 17719a1de308cea2d160778fd977825f10a07b49d738Adam Powell mTypes = types; 17729a1de308cea2d160778fd977825f10a07b49d738Adam Powell mGroupable = groupable; 17739a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 17749a1de308cea2d160778fd977825f10a07b49d738Adam Powell 17750d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell RouteCategory(int nameResId, int types, boolean groupable) { 17760d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell mNameResId = nameResId; 17770d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell mTypes = types; 17780d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell mGroupable = groupable; 17790d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell } 17800d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell 17819a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 17829a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @return the name of this route category 17839a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 17849a1de308cea2d160778fd977825f10a07b49d738Adam Powell public CharSequence getName() { 17850d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell return getName(sStatic.mResources); 17860d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell } 17870d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell 17880d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell /** 17890d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * Return the properly localized/configuration dependent name of this RouteCategory. 17900d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * 17910d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * @param context Context to resolve name resources 17920d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * @return the name of this route category 17930d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell */ 17940d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public CharSequence getName(Context context) { 17950d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell return getName(context.getResources()); 17960d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell } 17970d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell 17980d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell CharSequence getName(Resources res) { 17990d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell if (mNameResId != 0) { 18000d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell return res.getText(mNameResId); 18010d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell } 18029a1de308cea2d160778fd977825f10a07b49d738Adam Powell return mName; 18039a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 18049a1de308cea2d160778fd977825f10a07b49d738Adam Powell 18059a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 1806d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * Return the current list of routes in this category that have been added 1807d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * to the MediaRouter. 18089a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 1809d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * <p>This list will not include routes that are nested within RouteGroups. 1810d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * A RouteGroup is treated as a single route within its category.</p> 1811d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * 1812d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param out a List to fill with the routes in this category. If this parameter is 1813d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * non-null, it will be cleared, filled with the current routes with this 1814d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * category, and returned. If this parameter is null, a new List will be 1815d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * allocated to report the category's current routes. 1816d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @return A list with the routes in this category that have been added to the MediaRouter. 18179a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 1818d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell public List<RouteInfo> getRoutes(List<RouteInfo> out) { 1819d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell if (out == null) { 1820d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell out = new ArrayList<RouteInfo>(); 1821d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell } else { 1822d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell out.clear(); 1823d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell } 1824d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell 1825b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn final int count = getRouteCountStatic(); 1826d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell for (int i = 0; i < count; i++) { 1827b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn final RouteInfo route = getRouteAtStatic(i); 1828d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell if (route.mCategory == this) { 1829d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell out.add(route); 1830d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell } 1831d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell } 1832d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell return out; 18339a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 18349a1de308cea2d160778fd977825f10a07b49d738Adam Powell 18359a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 18369a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @return Flag set describing the route types supported by this category 18379a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 18389a1de308cea2d160778fd977825f10a07b49d738Adam Powell public int getSupportedTypes() { 18399a1de308cea2d160778fd977825f10a07b49d738Adam Powell return mTypes; 18409a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 18419a1de308cea2d160778fd977825f10a07b49d738Adam Powell 18429a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 18439a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Return whether or not this category supports grouping. 18449a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 18459a1de308cea2d160778fd977825f10a07b49d738Adam Powell * <p>If this method returns true, all routes obtained from this category 1846d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * via calls to {@link #getRouteAt(int)} will be {@link MediaRouter.RouteGroup}s.</p> 18479a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 18489a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @return true if this category supports 18499a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 18509a1de308cea2d160778fd977825f10a07b49d738Adam Powell public boolean isGroupable() { 18519a1de308cea2d160778fd977825f10a07b49d738Adam Powell return mGroupable; 18529a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 18539a1de308cea2d160778fd977825f10a07b49d738Adam Powell 1854705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell /** 1855705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell * @return true if this is the category reserved for system routes. 1856705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell * @hide 1857705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell */ 1858705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell public boolean isSystem() { 1859705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell return mIsSystem; 1860705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1861705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 18629a1de308cea2d160778fd977825f10a07b49d738Adam Powell public String toString() { 18639a1de308cea2d160778fd977825f10a07b49d738Adam Powell return "RouteCategory{ name=" + mName + " types=" + typesToString(mTypes) + 1864d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell " groupable=" + mGroupable + " }"; 18659a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 18669a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 18679a1de308cea2d160778fd977825f10a07b49d738Adam Powell 18689a1de308cea2d160778fd977825f10a07b49d738Adam Powell static class CallbackInfo { 18699a1de308cea2d160778fd977825f10a07b49d738Adam Powell public int type; 1870b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn public final Callback cb; 1871b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn public final MediaRouter router; 18729a1de308cea2d160778fd977825f10a07b49d738Adam Powell 1873b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn public CallbackInfo(Callback cb, int type, MediaRouter router) { 18749a1de308cea2d160778fd977825f10a07b49d738Adam Powell this.cb = cb; 18759a1de308cea2d160778fd977825f10a07b49d738Adam Powell this.type = type; 1876b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn this.router = router; 18779a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 18789a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 18799a1de308cea2d160778fd977825f10a07b49d738Adam Powell 18809a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 18819a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Interface for receiving events about media routing changes. 18829a1de308cea2d160778fd977825f10a07b49d738Adam Powell * All methods of this interface will be called from the application's main thread. 18839a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 18849a1de308cea2d160778fd977825f10a07b49d738Adam Powell * <p>A Callback will only receive events relevant to routes that the callback 18859a1de308cea2d160778fd977825f10a07b49d738Adam Powell * was registered for.</p> 18869a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 18879a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @see MediaRouter#addCallback(int, Callback) 18889a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @see MediaRouter#removeCallback(Callback) 18899a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 18900d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public static abstract class Callback { 18919a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 18929a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Called when the supplied route becomes selected as the active route 18939a1de308cea2d160778fd977825f10a07b49d738Adam Powell * for the given route type. 18949a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 1895d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param router the MediaRouter reporting the event 18969a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param type Type flag set indicating the routes that have been selected 18979a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param info Route that has been selected for the given route types 18989a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 18990d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public abstract void onRouteSelected(MediaRouter router, int type, RouteInfo info); 19009a1de308cea2d160778fd977825f10a07b49d738Adam Powell 19019a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 19029a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Called when the supplied route becomes unselected as the active route 19039a1de308cea2d160778fd977825f10a07b49d738Adam Powell * for the given route type. 19049a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 1905d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param router the MediaRouter reporting the event 19069a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param type Type flag set indicating the routes that have been unselected 19079a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param info Route that has been unselected for the given route types 19089a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 19090d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public abstract void onRouteUnselected(MediaRouter router, int type, RouteInfo info); 19109a1de308cea2d160778fd977825f10a07b49d738Adam Powell 19119a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 19129a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Called when a route for the specified type was added. 19139a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 1914d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param router the MediaRouter reporting the event 19159a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param info Route that has become available for use 19169a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 19170d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public abstract void onRouteAdded(MediaRouter router, RouteInfo info); 19189a1de308cea2d160778fd977825f10a07b49d738Adam Powell 19199a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 19209a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Called when a route for the specified type was removed. 19219a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 1922d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param router the MediaRouter reporting the event 19239a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param info Route that has been removed from availability 19249a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 19250d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public abstract void onRouteRemoved(MediaRouter router, RouteInfo info); 19269a1de308cea2d160778fd977825f10a07b49d738Adam Powell 19279a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 19289a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Called when an aspect of the indicated route has changed. 19299a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 19309a1de308cea2d160778fd977825f10a07b49d738Adam Powell * <p>This will not indicate that the types supported by this route have 19319a1de308cea2d160778fd977825f10a07b49d738Adam Powell * changed, only that cosmetic info such as name or status have been updated.</p> 19329a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 1933d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param router the MediaRouter reporting the event 19349a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param info The route that was changed 19359a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 19360d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public abstract void onRouteChanged(MediaRouter router, RouteInfo info); 1937d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell 1938d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell /** 1939d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * Called when a route is added to a group. 1940d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * 1941d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param router the MediaRouter reporting the event 1942d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param info The route that was added 1943d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param group The group the route was added to 1944d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param index The route index within group that info was added at 1945d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell */ 19460d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public abstract void onRouteGrouped(MediaRouter router, RouteInfo info, RouteGroup group, 19470d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell int index); 1948d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell 1949d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell /** 1950d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * Called when a route is removed from a group. 1951d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * 1952d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param router the MediaRouter reporting the event 1953d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param info The route that was removed 1954d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param group The group the route was removed from 1955d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell */ 19560d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public abstract void onRouteUngrouped(MediaRouter router, RouteInfo info, RouteGroup group); 19578e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 19588e37a85bf3dc39519942698dc90a3951306b934bAdam Powell /** 19598e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * Called when a route's volume changes. 19608e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * 19618e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * @param router the MediaRouter reporting the event 19628e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * @param info The route with altered volume 19638e37a85bf3dc39519942698dc90a3951306b934bAdam Powell */ 19648e37a85bf3dc39519942698dc90a3951306b934bAdam Powell public abstract void onRouteVolumeChanged(MediaRouter router, RouteInfo info); 196592130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown 196692130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown /** 196792130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * Called when a route's presentation display changes. 196892130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * <p> 196992130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * This method is called whenever the route's presentation display becomes 197092130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * available, is removes or has changes to some of its properties (such as its size). 197192130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * </p> 197292130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * 197392130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * @param router the MediaRouter reporting the event 197492130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * @param info The route whose presentation display changed 197592130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * 197692130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * @see RouteInfo#getPresentationDisplay() 197792130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown */ 197892130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown public void onRoutePresentationDisplayChanged(MediaRouter router, RouteInfo info) { 197992130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown } 19809a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 19819a1de308cea2d160778fd977825f10a07b49d738Adam Powell 19829a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 19830d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * Stub implementation of {@link MediaRouter.Callback}. 19840d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * Each abstract method is defined as a no-op. Override just the ones 19859a1de308cea2d160778fd977825f10a07b49d738Adam Powell * you need. 19869a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 19870d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public static class SimpleCallback extends Callback { 19889a1de308cea2d160778fd977825f10a07b49d738Adam Powell 19899a1de308cea2d160778fd977825f10a07b49d738Adam Powell @Override 1990d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell public void onRouteSelected(MediaRouter router, int type, RouteInfo info) { 19919a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 19929a1de308cea2d160778fd977825f10a07b49d738Adam Powell 19939a1de308cea2d160778fd977825f10a07b49d738Adam Powell @Override 1994d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell public void onRouteUnselected(MediaRouter router, int type, RouteInfo info) { 19959a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 19969a1de308cea2d160778fd977825f10a07b49d738Adam Powell 19979a1de308cea2d160778fd977825f10a07b49d738Adam Powell @Override 1998d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell public void onRouteAdded(MediaRouter router, RouteInfo info) { 19999a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 20009a1de308cea2d160778fd977825f10a07b49d738Adam Powell 20019a1de308cea2d160778fd977825f10a07b49d738Adam Powell @Override 2002d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell public void onRouteRemoved(MediaRouter router, RouteInfo info) { 20039a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 20049a1de308cea2d160778fd977825f10a07b49d738Adam Powell 20059a1de308cea2d160778fd977825f10a07b49d738Adam Powell @Override 2006d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell public void onRouteChanged(MediaRouter router, RouteInfo info) { 20079a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 20089a1de308cea2d160778fd977825f10a07b49d738Adam Powell 20099a1de308cea2d160778fd977825f10a07b49d738Adam Powell @Override 2010d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell public void onRouteGrouped(MediaRouter router, RouteInfo info, RouteGroup group, 2011d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell int index) { 20129a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 20139a1de308cea2d160778fd977825f10a07b49d738Adam Powell 20149a1de308cea2d160778fd977825f10a07b49d738Adam Powell @Override 2015d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell public void onRouteUngrouped(MediaRouter router, RouteInfo info, RouteGroup group) { 20169a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 2017d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell 20188e37a85bf3dc39519942698dc90a3951306b934bAdam Powell @Override 20198e37a85bf3dc39519942698dc90a3951306b934bAdam Powell public void onRouteVolumeChanged(MediaRouter router, RouteInfo info) { 20208e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 20219a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 20221357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 20231357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi static class VolumeCallbackInfo { 20241357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public final VolumeCallback vcb; 20251357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public final RouteInfo route; 20261357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 20271357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public VolumeCallbackInfo(VolumeCallback vcb, RouteInfo route) { 20281357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi this.vcb = vcb; 20291357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi this.route = route; 20301357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 20311357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 20321357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 20331357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 20341357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * Interface for receiving events about volume changes. 20351357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * All methods of this interface will be called from the application's main thread. 20361357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * 20371357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * <p>A VolumeCallback will only receive events relevant to routes that the callback 20381357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * was registered for.</p> 20391357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * 20401357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @see UserRouteInfo#setVolumeCallback(VolumeCallback) 20411357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 20421357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public static abstract class VolumeCallback { 20431357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 20441357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * Called when the volume for the route should be increased or decreased. 20451357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @param info the route affected by this event 20461357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @param direction an integer indicating whether the volume is to be increased 20471357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * (positive value) or decreased (negative value). 20481357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * For bundled changes, the absolute value indicates the number of changes 20491357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * in the same direction, e.g. +3 corresponds to three "volume up" changes. 20501357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 20511357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public abstract void onVolumeUpdateRequest(RouteInfo info, int direction); 20521357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 20531357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * Called when the volume for the route should be set to the given value 20541357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @param info the route affected by this event 20551357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @param volume an integer indicating the new volume value that should be used, always 20561357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * between 0 and the value set by {@link UserRouteInfo#setVolumeMax(int)}. 20571357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 20581357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public abstract void onVolumeSetRequest(RouteInfo info, int volume); 20591357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 20601357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 20618e37a85bf3dc39519942698dc90a3951306b934bAdam Powell static class VolumeChangeReceiver extends BroadcastReceiver { 20628e37a85bf3dc39519942698dc90a3951306b934bAdam Powell @Override 20638e37a85bf3dc39519942698dc90a3951306b934bAdam Powell public void onReceive(Context context, Intent intent) { 20648e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (intent.getAction().equals(AudioManager.VOLUME_CHANGED_ACTION)) { 20658e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final int streamType = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, 20668e37a85bf3dc39519942698dc90a3951306b934bAdam Powell -1); 20678e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (streamType != AudioManager.STREAM_MUSIC) { 20688e37a85bf3dc39519942698dc90a3951306b934bAdam Powell return; 20698e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 20708e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 20718e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final int newVolume = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, 0); 20728e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final int oldVolume = intent.getIntExtra( 20738e37a85bf3dc39519942698dc90a3951306b934bAdam Powell AudioManager.EXTRA_PREV_VOLUME_STREAM_VALUE, 0); 20748e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (newVolume != oldVolume) { 20758e37a85bf3dc39519942698dc90a3951306b934bAdam Powell systemVolumeChanged(newVolume); 20768e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 20778e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 20788e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 2079705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 20808e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 2081705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell static class WifiDisplayStatusChangedReceiver extends BroadcastReceiver { 2082705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell @Override 2083705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell public void onReceive(Context context, Intent intent) { 2084705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell if (intent.getAction().equals(DisplayManager.ACTION_WIFI_DISPLAY_STATUS_CHANGED)) { 2085705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell updateWifiDisplayStatus((WifiDisplayStatus) intent.getParcelableExtra( 2086705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell DisplayManager.EXTRA_WIFI_DISPLAY_STATUS)); 2087705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 2088705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 20898e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 20909a1de308cea2d160778fd977825f10a07b49d738Adam Powell} 2091