MediaRouter.java revision ef3c9e9b057a5aac2d0d012e8e6385660478e203
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 19af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brownimport android.Manifest; 20ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackbornimport android.app.ActivityThread; 218e37a85bf3dc39519942698dc90a3951306b934bAdam Powellimport android.content.BroadcastReceiver; 229a1de308cea2d160778fd977825f10a07b49d738Adam Powellimport android.content.Context; 238e37a85bf3dc39519942698dc90a3951306b934bAdam Powellimport android.content.Intent; 248e37a85bf3dc39519942698dc90a3951306b934bAdam Powellimport android.content.IntentFilter; 25af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brownimport android.content.pm.PackageManager; 26b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackbornimport android.content.res.Resources; 27ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powellimport android.graphics.drawable.Drawable; 28705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powellimport android.hardware.display.DisplayManager; 29705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powellimport android.hardware.display.WifiDisplay; 30705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powellimport android.hardware.display.WifiDisplayStatus; 315d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErikimport android.media.session.MediaSession; 329a1de308cea2d160778fd977825f10a07b49d738Adam Powellimport android.os.Handler; 33632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackbornimport android.os.IBinder; 34af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brownimport android.os.Process; 35632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackbornimport android.os.RemoteException; 36632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackbornimport android.os.ServiceManager; 3769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brownimport android.os.UserHandle; 38632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackbornimport android.text.TextUtils; 399a1de308cea2d160778fd977825f10a07b49d738Adam Powellimport android.util.Log; 40705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powellimport android.view.Display; 419a1de308cea2d160778fd977825f10a07b49d738Adam Powell 429a1de308cea2d160778fd977825f10a07b49d738Adam Powellimport java.util.ArrayList; 439a1de308cea2d160778fd977825f10a07b49d738Adam Powellimport java.util.HashMap; 44d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powellimport java.util.List; 45e6585b32ea586743258a5457e2184ffc087f2d2fKenny Rootimport java.util.Objects; 4639d5c6172503620ac3761148adac5fd7fa20d02dAdam Powellimport java.util.concurrent.CopyOnWriteArrayList; 479a1de308cea2d160778fd977825f10a07b49d738Adam Powell 489a1de308cea2d160778fd977825f10a07b49d738Adam Powell/** 499a1de308cea2d160778fd977825f10a07b49d738Adam Powell * MediaRouter allows applications to control the routing of media channels 509a1de308cea2d160778fd977825f10a07b49d738Adam Powell * and streams from the current device to external speakers and destination devices. 519a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 52b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn * <p>A MediaRouter is retrieved through {@link Context#getSystemService(String) 53b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn * Context.getSystemService()} of a {@link Context#MEDIA_ROUTER_SERVICE 54b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn * Context.MEDIA_ROUTER_SERVICE}. 55b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn * 56b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn * <p>The media router API is not thread-safe; all interactions with it must be 57b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn * done from the main thread of the process.</p> 589a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 599a1de308cea2d160778fd977825f10a07b49d738Adam Powellpublic class MediaRouter { 609a1de308cea2d160778fd977825f10a07b49d738Adam Powell private static final String TAG = "MediaRouter"; 6169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); 629a1de308cea2d160778fd977825f10a07b49d738Adam Powell 6392130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown static class Static implements DisplayManager.DisplayListener { 6469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final Context mAppContext; 65b35c445f34e1a18e17aef3e3dfbc1c39b4d1815cAdam Powell final Resources mResources; 66632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn final IAudioService mAudioService; 67705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell final DisplayManager mDisplayService; 6869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final IMediaRouterService mMediaRouterService; 69b35c445f34e1a18e17aef3e3dfbc1c39b4d1815cAdam Powell final Handler mHandler; 7039d5c6172503620ac3761148adac5fd7fa20d02dAdam Powell final CopyOnWriteArrayList<CallbackInfo> mCallbacks = 7139d5c6172503620ac3761148adac5fd7fa20d02dAdam Powell new CopyOnWriteArrayList<CallbackInfo>(); 72b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn 73b35c445f34e1a18e17aef3e3dfbc1c39b4d1815cAdam Powell final ArrayList<RouteInfo> mRoutes = new ArrayList<RouteInfo>(); 74b35c445f34e1a18e17aef3e3dfbc1c39b4d1815cAdam Powell final ArrayList<RouteCategory> mCategories = new ArrayList<RouteCategory>(); 75b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn 76b35c445f34e1a18e17aef3e3dfbc1c39b4d1815cAdam Powell final RouteCategory mSystemCategory; 77632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn 78705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell final AudioRoutesInfo mCurAudioRoutesInfo = new AudioRoutesInfo(); 79b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn 80705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell RouteInfo mDefaultAudioVideo; 81b35c445f34e1a18e17aef3e3dfbc1c39b4d1815cAdam Powell RouteInfo mBluetoothA2dpRoute; 82b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn 83b35c445f34e1a18e17aef3e3dfbc1c39b4d1815cAdam Powell RouteInfo mSelectedRoute; 849a1de308cea2d160778fd977825f10a07b49d738Adam Powell 85af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown final boolean mCanConfigureWifiDisplays; 8666f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown boolean mActivelyScanningWifiDisplays; 87ce468a35b388ca46578934706b38dbae94941643Jeff Brown String mPreviousActiveWifiDisplayAddress; 88705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 8969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown int mDiscoveryRequestRouteTypes; 9069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown boolean mDiscoverRequestActiveScan; 9169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 9269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown int mCurrentUserId = -1; 9369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown IMediaRouterClient mClient; 9469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown MediaRouterClientState mClientState; 9569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 96705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell final IAudioRoutesObserver.Stub mAudioRoutesObserver = new IAudioRoutesObserver.Stub() { 9766f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown @Override 98632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn public void dispatchAudioRoutesChanged(final AudioRoutesInfo newRoutes) { 99632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn mHandler.post(new Runnable() { 100632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn @Override public void run() { 101705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell updateAudioRoutes(newRoutes); 102632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } 103632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn }); 104632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } 105632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn }; 106632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn 107b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn Static(Context appContext) { 10869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mAppContext = appContext; 109b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn mResources = Resources.getSystem(); 110b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn mHandler = new Handler(appContext.getMainLooper()); 1119a1de308cea2d160778fd977825f10a07b49d738Adam Powell 112632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn IBinder b = ServiceManager.getService(Context.AUDIO_SERVICE); 113632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn mAudioService = IAudioService.Stub.asInterface(b); 1149a1de308cea2d160778fd977825f10a07b49d738Adam Powell 115705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell mDisplayService = (DisplayManager) appContext.getSystemService(Context.DISPLAY_SERVICE); 116705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 11769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mMediaRouterService = IMediaRouterService.Stub.asInterface( 11869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown ServiceManager.getService(Context.MEDIA_ROUTER_SERVICE)); 11969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 120dd0a19266d5c837069da1ea188744d54c8d723a8Adam Powell mSystemCategory = new RouteCategory( 121dd0a19266d5c837069da1ea188744d54c8d723a8Adam Powell com.android.internal.R.string.default_audio_route_category_name, 122705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell ROUTE_TYPE_LIVE_AUDIO | ROUTE_TYPE_LIVE_VIDEO, false); 123705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell mSystemCategory.mIsSystem = true; 124af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown 125af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown // Only the system can configure wifi displays. The display manager 126af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown // enforces this with a permission check. Set a flag here so that we 127af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown // know whether this process is actually allowed to scan and connect. 128af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown mCanConfigureWifiDisplays = appContext.checkPermission( 129af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown Manifest.permission.CONFIGURE_WIFI_DISPLAY, 130af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown Process.myPid(), Process.myUid()) == PackageManager.PERMISSION_GRANTED; 131b35c445f34e1a18e17aef3e3dfbc1c39b4d1815cAdam Powell } 132b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn 133b35c445f34e1a18e17aef3e3dfbc1c39b4d1815cAdam Powell // Called after sStatic is initialized 1348e37a85bf3dc39519942698dc90a3951306b934bAdam Powell void startMonitoringRoutes(Context appContext) { 135705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell mDefaultAudioVideo = new RouteInfo(mSystemCategory); 136705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell mDefaultAudioVideo.mNameResId = com.android.internal.R.string.default_audio_route_name; 137705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell mDefaultAudioVideo.mSupportedTypes = ROUTE_TYPE_LIVE_AUDIO | ROUTE_TYPE_LIVE_VIDEO; 1385830b0b33618940d65197cec99d697b21908fec8Chong Zhang mDefaultAudioVideo.updatePresentationDisplay(); 1392ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell addRouteStatic(mDefaultAudioVideo); 140632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn 1412ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell // This will select the active wifi display route if there is one. 1422ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell updateWifiDisplayStatus(mDisplayService.getWifiDisplayStatus()); 1432ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell 1442ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell appContext.registerReceiver(new WifiDisplayStatusChangedReceiver(), 1452ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell new IntentFilter(DisplayManager.ACTION_WIFI_DISPLAY_STATUS_CHANGED)); 1468e37a85bf3dc39519942698dc90a3951306b934bAdam Powell appContext.registerReceiver(new VolumeChangeReceiver(), 1478e37a85bf3dc39519942698dc90a3951306b934bAdam Powell new IntentFilter(AudioManager.VOLUME_CHANGED_ACTION)); 1488e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 14992130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown mDisplayService.registerDisplayListener(this, mHandler); 15092130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown 151705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell AudioRoutesInfo newAudioRoutes = null; 152632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn try { 153705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell newAudioRoutes = mAudioService.startWatchingRoutes(mAudioRoutesObserver); 154632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } catch (RemoteException e) { 155632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } 156705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell if (newAudioRoutes != null) { 1572ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell // This will select the active BT route if there is one and the current 1582ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell // selected route is the default system route, or if there is no selected 1592ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell // route yet. 160705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell updateAudioRoutes(newAudioRoutes); 161632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } 162705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 16369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Bind to the media router service. 16469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown rebindAsUser(UserHandle.myUserId()); 16569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 1662ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell // Select the default route if the above didn't sync us up 1672ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell // appropriately with relevant system state. 1682ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell if (mSelectedRoute == null) { 16969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown selectDefaultRouteStatic(); 1702ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell } 171632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } 172632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn 173705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell void updateAudioRoutes(AudioRoutesInfo newRoutes) { 174705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell if (newRoutes.mMainType != mCurAudioRoutesInfo.mMainType) { 175705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell mCurAudioRoutesInfo.mMainType = newRoutes.mMainType; 176632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn int name; 177632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn if ((newRoutes.mMainType&AudioRoutesInfo.MAIN_HEADPHONES) != 0 178632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn || (newRoutes.mMainType&AudioRoutesInfo.MAIN_HEADSET) != 0) { 179632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn name = com.android.internal.R.string.default_audio_route_name_headphones; 180632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } else if ((newRoutes.mMainType&AudioRoutesInfo.MAIN_DOCK_SPEAKERS) != 0) { 181632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn name = com.android.internal.R.string.default_audio_route_name_dock_speakers; 182632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } else if ((newRoutes.mMainType&AudioRoutesInfo.MAIN_HDMI) != 0) { 1834131a37366d59b5e61f55c4e48d2b22ee0c4cad4Adam Powell name = com.android.internal.R.string.default_media_route_name_hdmi; 184632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } else { 185632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn name = com.android.internal.R.string.default_audio_route_name; 186632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } 187705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell sStatic.mDefaultAudioVideo.mNameResId = name; 188705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell dispatchRouteChanged(sStatic.mDefaultAudioVideo); 189632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } 190bcf21e913af7252fb1994e07b6cf179321ecd049Adam Powell 1913f369684e13dfea0ba8ea134f3e95930b0dd7df0Adam Powell final int mainType = mCurAudioRoutesInfo.mMainType; 1923f369684e13dfea0ba8ea134f3e95930b0dd7df0Adam Powell 193bcf21e913af7252fb1994e07b6cf179321ecd049Adam Powell boolean a2dpEnabled; 194bcf21e913af7252fb1994e07b6cf179321ecd049Adam Powell try { 195bcf21e913af7252fb1994e07b6cf179321ecd049Adam Powell a2dpEnabled = mAudioService.isBluetoothA2dpOn(); 196bcf21e913af7252fb1994e07b6cf179321ecd049Adam Powell } catch (RemoteException e) { 197bcf21e913af7252fb1994e07b6cf179321ecd049Adam Powell Log.e(TAG, "Error querying Bluetooth A2DP state", e); 198bcf21e913af7252fb1994e07b6cf179321ecd049Adam Powell a2dpEnabled = false; 199bcf21e913af7252fb1994e07b6cf179321ecd049Adam Powell } 200bcf21e913af7252fb1994e07b6cf179321ecd049Adam Powell 201705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell if (!TextUtils.equals(newRoutes.mBluetoothName, mCurAudioRoutesInfo.mBluetoothName)) { 202705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell mCurAudioRoutesInfo.mBluetoothName = newRoutes.mBluetoothName; 203705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell if (mCurAudioRoutesInfo.mBluetoothName != null) { 204632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn if (sStatic.mBluetoothA2dpRoute == null) { 205632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn final RouteInfo info = new RouteInfo(sStatic.mSystemCategory); 206705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell info.mName = mCurAudioRoutesInfo.mBluetoothName; 20756d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown info.mDescription = sStatic.mResources.getText( 20856d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown com.android.internal.R.string.bluetooth_a2dp_audio_route_name); 209632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn info.mSupportedTypes = ROUTE_TYPE_LIVE_AUDIO; 210632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn sStatic.mBluetoothA2dpRoute = info; 2112ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell addRouteStatic(sStatic.mBluetoothA2dpRoute); 212632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } else { 213705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell sStatic.mBluetoothA2dpRoute.mName = mCurAudioRoutesInfo.mBluetoothName; 214632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn dispatchRouteChanged(sStatic.mBluetoothA2dpRoute); 215632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } 216632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } else if (sStatic.mBluetoothA2dpRoute != null) { 21769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown removeRouteStatic(sStatic.mBluetoothA2dpRoute); 218632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn sStatic.mBluetoothA2dpRoute = null; 219632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } 220632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } 221bcf21e913af7252fb1994e07b6cf179321ecd049Adam Powell 222bcf21e913af7252fb1994e07b6cf179321ecd049Adam Powell if (mBluetoothA2dpRoute != null) { 2233f369684e13dfea0ba8ea134f3e95930b0dd7df0Adam Powell if (mainType != AudioRoutesInfo.MAIN_SPEAKER && 2243f369684e13dfea0ba8ea134f3e95930b0dd7df0Adam Powell mSelectedRoute == mBluetoothA2dpRoute && !a2dpEnabled) { 22569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown selectRouteStatic(ROUTE_TYPE_LIVE_AUDIO, mDefaultAudioVideo, false); 2263f369684e13dfea0ba8ea134f3e95930b0dd7df0Adam Powell } else if ((mSelectedRoute == mDefaultAudioVideo || mSelectedRoute == null) && 2272ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell a2dpEnabled) { 22869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown selectRouteStatic(ROUTE_TYPE_LIVE_AUDIO, mBluetoothA2dpRoute, false); 229bcf21e913af7252fb1994e07b6cf179321ecd049Adam Powell } 230bcf21e913af7252fb1994e07b6cf179321ecd049Adam Powell } 231b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn } 23292130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown 23369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown void updateDiscoveryRequest() { 23469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // What are we looking for today? 23569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown int routeTypes = 0; 23669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown int passiveRouteTypes = 0; 23769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown boolean activeScan = false; 23869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown boolean activeScanWifiDisplay = false; 23969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final int count = mCallbacks.size(); 24069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown for (int i = 0; i < count; i++) { 24169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown CallbackInfo cbi = mCallbacks.get(i); 24269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if ((cbi.flags & (CALLBACK_FLAG_PERFORM_ACTIVE_SCAN 24369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown | CALLBACK_FLAG_REQUEST_DISCOVERY)) != 0) { 24469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Discovery explicitly requested. 24569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown routeTypes |= cbi.type; 24669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } else if ((cbi.flags & CALLBACK_FLAG_PASSIVE_DISCOVERY) != 0) { 24769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Discovery only passively requested. 24869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown passiveRouteTypes |= cbi.type; 24969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } else { 25069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Legacy case since applications don't specify the discovery flag. 25169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Unfortunately we just have to assume they always need discovery 25269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // whenever they have a callback registered. 25369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown routeTypes |= cbi.type; 25469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 25569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if ((cbi.flags & CALLBACK_FLAG_PERFORM_ACTIVE_SCAN) != 0) { 25669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown activeScan = true; 257af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown if ((cbi.type & ROUTE_TYPE_REMOTE_DISPLAY) != 0) { 25869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown activeScanWifiDisplay = true; 25969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 26069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 26169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 26269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (routeTypes != 0 || activeScan) { 26369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // If someone else requests discovery then enable the passive listeners. 26469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // This is used by the MediaRouteButton and MediaRouteActionProvider since 26569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // they don't receive lifecycle callbacks from the Activity. 26669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown routeTypes |= passiveRouteTypes; 26769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 26869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 26969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Update wifi display scanning. 270ce468a35b388ca46578934706b38dbae94941643Jeff Brown // TODO: All of this should be managed by the media router service. 271ce468a35b388ca46578934706b38dbae94941643Jeff Brown if (mCanConfigureWifiDisplays) { 272ce468a35b388ca46578934706b38dbae94941643Jeff Brown if (mSelectedRoute != null 273ce468a35b388ca46578934706b38dbae94941643Jeff Brown && mSelectedRoute.matchesTypes(ROUTE_TYPE_REMOTE_DISPLAY)) { 274ce468a35b388ca46578934706b38dbae94941643Jeff Brown // Don't scan while already connected to a remote display since 275ce468a35b388ca46578934706b38dbae94941643Jeff Brown // it may interfere with the ongoing transmission. 276ce468a35b388ca46578934706b38dbae94941643Jeff Brown activeScanWifiDisplay = false; 27766f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown } 278ce468a35b388ca46578934706b38dbae94941643Jeff Brown if (activeScanWifiDisplay) { 279ce468a35b388ca46578934706b38dbae94941643Jeff Brown if (!mActivelyScanningWifiDisplays) { 280ce468a35b388ca46578934706b38dbae94941643Jeff Brown mActivelyScanningWifiDisplays = true; 281ce468a35b388ca46578934706b38dbae94941643Jeff Brown mDisplayService.startWifiDisplayScan(); 282ce468a35b388ca46578934706b38dbae94941643Jeff Brown } 283ce468a35b388ca46578934706b38dbae94941643Jeff Brown } else { 284ce468a35b388ca46578934706b38dbae94941643Jeff Brown if (mActivelyScanningWifiDisplays) { 285ce468a35b388ca46578934706b38dbae94941643Jeff Brown mActivelyScanningWifiDisplays = false; 286ce468a35b388ca46578934706b38dbae94941643Jeff Brown mDisplayService.stopWifiDisplayScan(); 287ce468a35b388ca46578934706b38dbae94941643Jeff Brown } 28866f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown } 28966f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown } 29066f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown 29169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Tell the media router service all about it. 29269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (routeTypes != mDiscoveryRequestRouteTypes 29369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown || activeScan != mDiscoverRequestActiveScan) { 29469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mDiscoveryRequestRouteTypes = routeTypes; 29569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mDiscoverRequestActiveScan = activeScan; 29669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown publishClientDiscoveryRequest(); 29766f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown } 29866f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown } 29966f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown 30092130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown @Override 30192130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown public void onDisplayAdded(int displayId) { 30292130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown updatePresentationDisplays(displayId); 30392130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown } 30492130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown 30592130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown @Override 30692130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown public void onDisplayChanged(int displayId) { 30792130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown updatePresentationDisplays(displayId); 30892130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown } 30992130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown 31092130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown @Override 31192130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown public void onDisplayRemoved(int displayId) { 31292130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown updatePresentationDisplays(displayId); 31392130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown } 31492130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown 31592130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown public Display[] getAllPresentationDisplays() { 31692130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown return mDisplayService.getDisplays(DisplayManager.DISPLAY_CATEGORY_PRESENTATION); 31792130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown } 31892130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown 31992130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown private void updatePresentationDisplays(int changedDisplayId) { 32092130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown final int count = mRoutes.size(); 32192130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown for (int i = 0; i < count; i++) { 3225830b0b33618940d65197cec99d697b21908fec8Chong Zhang final RouteInfo route = mRoutes.get(i); 3235830b0b33618940d65197cec99d697b21908fec8Chong Zhang if (route.updatePresentationDisplay() || (route.mPresentationDisplay != null 3245830b0b33618940d65197cec99d697b21908fec8Chong Zhang && route.mPresentationDisplay.getDisplayId() == changedDisplayId)) { 3255830b0b33618940d65197cec99d697b21908fec8Chong Zhang dispatchRoutePresentationDisplayChanged(route); 32692130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown } 32792130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown } 32892130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown } 32969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 33069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown void setSelectedRoute(RouteInfo info, boolean explicit) { 33169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Must be non-reentrant. 33269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mSelectedRoute = info; 33369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown publishClientSelectedRoute(explicit); 33469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 33569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 33669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown void rebindAsUser(int userId) { 33769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (mCurrentUserId != userId || userId < 0 || mClient == null) { 33869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (mClient != null) { 33969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown try { 34069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mMediaRouterService.unregisterClient(mClient); 34169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } catch (RemoteException ex) { 34269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Log.e(TAG, "Unable to unregister media router client.", ex); 34369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 34469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mClient = null; 34569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 34669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 34769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mCurrentUserId = userId; 34869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 34969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown try { 35069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Client client = new Client(); 35169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mMediaRouterService.registerClientAsUser(client, 35269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mAppContext.getPackageName(), userId); 35369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mClient = client; 35469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } catch (RemoteException ex) { 35569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Log.e(TAG, "Unable to register media router client.", ex); 35669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 35769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 35869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown publishClientDiscoveryRequest(); 35969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown publishClientSelectedRoute(false); 36069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown updateClientState(); 36169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 36269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 36369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 36469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown void publishClientDiscoveryRequest() { 36569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (mClient != null) { 36669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown try { 36769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mMediaRouterService.setDiscoveryRequest(mClient, 36869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mDiscoveryRequestRouteTypes, mDiscoverRequestActiveScan); 36969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } catch (RemoteException ex) { 37069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Log.e(TAG, "Unable to publish media router client discovery request.", ex); 37169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 37269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 37369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 37469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 37569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown void publishClientSelectedRoute(boolean explicit) { 37669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (mClient != null) { 37769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown try { 37869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mMediaRouterService.setSelectedRoute(mClient, 37969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mSelectedRoute != null ? mSelectedRoute.mGlobalRouteId : null, 38069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown explicit); 38169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } catch (RemoteException ex) { 38269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Log.e(TAG, "Unable to publish media router client selected route.", ex); 38369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 38469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 38569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 38669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 38769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown void updateClientState() { 38869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Update the client state. 38969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mClientState = null; 39069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (mClient != null) { 39169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown try { 39269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mClientState = mMediaRouterService.getState(mClient); 39369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } catch (RemoteException ex) { 39469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Log.e(TAG, "Unable to retrieve media router client state.", ex); 39569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 39669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 39769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final ArrayList<MediaRouterClientState.RouteInfo> globalRoutes = 39869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mClientState != null ? mClientState.routes : null; 39969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final String globallySelectedRouteId = mClientState != null ? 40069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mClientState.globallySelectedRouteId : null; 40169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 40269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Add or update routes. 40369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final int globalRouteCount = globalRoutes != null ? globalRoutes.size() : 0; 40469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown for (int i = 0; i < globalRouteCount; i++) { 40569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final MediaRouterClientState.RouteInfo globalRoute = globalRoutes.get(i); 40669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown RouteInfo route = findGlobalRoute(globalRoute.id); 40769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (route == null) { 40869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route = makeGlobalRoute(globalRoute); 40969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown addRouteStatic(route); 41069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } else { 41169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown updateGlobalRoute(route, globalRoute); 41269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 41369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 41469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 41569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Synchronize state with the globally selected route. 41669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (globallySelectedRouteId != null) { 41769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final RouteInfo route = findGlobalRoute(globallySelectedRouteId); 41869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (route == null) { 41969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Log.w(TAG, "Could not find new globally selected route: " 42069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown + globallySelectedRouteId); 42169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } else if (route != mSelectedRoute) { 42269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (DEBUG) { 42369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Log.d(TAG, "Selecting new globally selected route: " + route); 42469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 42569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown selectRouteStatic(route.mSupportedTypes, route, false); 42669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 42769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } else if (mSelectedRoute != null && mSelectedRoute.mGlobalRouteId != null) { 42869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (DEBUG) { 42969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Log.d(TAG, "Unselecting previous globally selected route: " + mSelectedRoute); 43069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 43169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown selectDefaultRouteStatic(); 43269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 43369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 43469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Remove defunct routes. 43569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown outer: for (int i = mRoutes.size(); i-- > 0; ) { 43669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final RouteInfo route = mRoutes.get(i); 43769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final String globalRouteId = route.mGlobalRouteId; 43869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (globalRouteId != null) { 43969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown for (int j = 0; j < globalRouteCount; j++) { 44069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown MediaRouterClientState.RouteInfo globalRoute = globalRoutes.get(j); 44169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (globalRouteId.equals(globalRoute.id)) { 44269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown continue outer; // found 44369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 44469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 44569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // not found 44669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown removeRouteStatic(route); 44769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 44869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 44969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 45069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 45169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown void requestSetVolume(RouteInfo route, int volume) { 45269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (route.mGlobalRouteId != null && mClient != null) { 45369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown try { 45469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mMediaRouterService.requestSetVolume(mClient, 45569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mGlobalRouteId, volume); 45669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } catch (RemoteException ex) { 45769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Log.w(TAG, "Unable to request volume change.", ex); 45869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 45969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 46069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 46169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 46269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown void requestUpdateVolume(RouteInfo route, int direction) { 46369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (route.mGlobalRouteId != null && mClient != null) { 46469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown try { 46569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mMediaRouterService.requestUpdateVolume(mClient, 46669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mGlobalRouteId, direction); 46769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } catch (RemoteException ex) { 46869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Log.w(TAG, "Unable to request volume change.", ex); 46969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 47069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 47169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 47269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 47369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown RouteInfo makeGlobalRoute(MediaRouterClientState.RouteInfo globalRoute) { 47469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown RouteInfo route = new RouteInfo(sStatic.mSystemCategory); 47569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mGlobalRouteId = globalRoute.id; 47669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mName = globalRoute.name; 47769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mDescription = globalRoute.description; 47869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mSupportedTypes = globalRoute.supportedTypes; 47969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mEnabled = globalRoute.enabled; 48039ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown route.setRealStatusCode(globalRoute.statusCode); 48169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mPlaybackType = globalRoute.playbackType; 48269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mPlaybackStream = globalRoute.playbackStream; 48369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mVolume = globalRoute.volume; 48469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mVolumeMax = globalRoute.volumeMax; 48569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mVolumeHandling = globalRoute.volumeHandling; 4865830b0b33618940d65197cec99d697b21908fec8Chong Zhang route.mPresentationDisplayId = globalRoute.presentationDisplayId; 4875830b0b33618940d65197cec99d697b21908fec8Chong Zhang route.updatePresentationDisplay(); 48869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return route; 48969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 49069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 49169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown void updateGlobalRoute(RouteInfo route, MediaRouterClientState.RouteInfo globalRoute) { 49269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown boolean changed = false; 49369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown boolean volumeChanged = false; 49469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown boolean presentationDisplayChanged = false; 49569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 496e6585b32ea586743258a5457e2184ffc087f2d2fKenny Root if (!Objects.equals(route.mName, globalRoute.name)) { 49769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mName = globalRoute.name; 49869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown changed = true; 49969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 500e6585b32ea586743258a5457e2184ffc087f2d2fKenny Root if (!Objects.equals(route.mDescription, globalRoute.description)) { 50169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mDescription = globalRoute.description; 50269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown changed = true; 50369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 504af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown final int oldSupportedTypes = route.mSupportedTypes; 505af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown if (oldSupportedTypes != globalRoute.supportedTypes) { 50669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mSupportedTypes = globalRoute.supportedTypes; 50769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown changed = true; 50869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 50969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (route.mEnabled != globalRoute.enabled) { 51069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mEnabled = globalRoute.enabled; 51169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown changed = true; 51269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 51339ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown if (route.mRealStatusCode != globalRoute.statusCode) { 51439ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown route.setRealStatusCode(globalRoute.statusCode); 51569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown changed = true; 51669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 51769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (route.mPlaybackType != globalRoute.playbackType) { 51869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mPlaybackType = globalRoute.playbackType; 51969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown changed = true; 52069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 52169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (route.mPlaybackStream != globalRoute.playbackStream) { 52269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mPlaybackStream = globalRoute.playbackStream; 52369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown changed = true; 52469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 52569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (route.mVolume != globalRoute.volume) { 52669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mVolume = globalRoute.volume; 52769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown changed = true; 52869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown volumeChanged = true; 52969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 53069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (route.mVolumeMax != globalRoute.volumeMax) { 53169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mVolumeMax = globalRoute.volumeMax; 53269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown changed = true; 53369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown volumeChanged = true; 53469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 53569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (route.mVolumeHandling != globalRoute.volumeHandling) { 53669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mVolumeHandling = globalRoute.volumeHandling; 53769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown changed = true; 53869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown volumeChanged = true; 53969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 5405830b0b33618940d65197cec99d697b21908fec8Chong Zhang if (route.mPresentationDisplayId != globalRoute.presentationDisplayId) { 5415830b0b33618940d65197cec99d697b21908fec8Chong Zhang route.mPresentationDisplayId = globalRoute.presentationDisplayId; 5425830b0b33618940d65197cec99d697b21908fec8Chong Zhang route.updatePresentationDisplay(); 54369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown changed = true; 54469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown presentationDisplayChanged = true; 54569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 54669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 54769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (changed) { 548af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown dispatchRouteChanged(route, oldSupportedTypes); 54969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 55069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (volumeChanged) { 55169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown dispatchRouteVolumeChanged(route); 55269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 55369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (presentationDisplayChanged) { 55469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown dispatchRoutePresentationDisplayChanged(route); 55569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 55669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 55769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 55869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown RouteInfo findGlobalRoute(String globalRouteId) { 55969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final int count = mRoutes.size(); 56069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown for (int i = 0; i < count; i++) { 56169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final RouteInfo route = mRoutes.get(i); 56269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (globalRouteId.equals(route.mGlobalRouteId)) { 56369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return route; 56469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 56569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 56669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return null; 56769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 56869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 56969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final class Client extends IMediaRouterClient.Stub { 57069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown @Override 57169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public void onStateChanged() { 57269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mHandler.post(new Runnable() { 57369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown @Override 57469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public void run() { 57569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (Client.this == mClient) { 57669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown updateClientState(); 57769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 57869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 57969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown }); 58069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 58169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 582b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn } 5839a1de308cea2d160778fd977825f10a07b49d738Adam Powell 584b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn static Static sStatic; 5859a1de308cea2d160778fd977825f10a07b49d738Adam Powell 5869a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 5879a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Route type flag for live audio. 5889a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 5899a1de308cea2d160778fd977825f10a07b49d738Adam Powell * <p>A device that supports live audio routing will allow the media audio stream 5909a1de308cea2d160778fd977825f10a07b49d738Adam Powell * to be routed to supported destinations. This can include internal speakers or 5919a1de308cea2d160778fd977825f10a07b49d738Adam Powell * audio jacks on the device itself, A2DP devices, and more.</p> 5929a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 5939a1de308cea2d160778fd977825f10a07b49d738Adam Powell * <p>Once initiated this routing is transparent to the application. All audio 5949a1de308cea2d160778fd977825f10a07b49d738Adam Powell * played on the media stream will be routed to the selected destination.</p> 5959a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 59669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public static final int ROUTE_TYPE_LIVE_AUDIO = 1 << 0; 5979a1de308cea2d160778fd977825f10a07b49d738Adam Powell 5989a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 599705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell * Route type flag for live video. 600705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell * 601705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell * <p>A device that supports live video routing will allow a mirrored version 602705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell * of the device's primary display or a customized 603705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell * {@link android.app.Presentation Presentation} to be routed to supported destinations.</p> 604705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell * 605705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell * <p>Once initiated, display mirroring is transparent to the application. 606705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell * While remote routing is active the application may use a 607705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell * {@link android.app.Presentation Presentation} to replace the mirrored view 608705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell * on the external display with different content.</p> 60992130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * 61092130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * @see RouteInfo#getPresentationDisplay() 61192130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * @see android.app.Presentation 612705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell */ 61369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public static final int ROUTE_TYPE_LIVE_VIDEO = 1 << 1; 61469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 61569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown /** 61669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * Temporary interop constant to identify remote displays. 61769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * @hide To be removed when media router API is updated. 61869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown */ 61969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public static final int ROUTE_TYPE_REMOTE_DISPLAY = 1 << 2; 620705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 621705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell /** 6229a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Route type flag for application-specific usage. 6239a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 6249a1de308cea2d160778fd977825f10a07b49d738Adam Powell * <p>Unlike other media route types, user routes are managed by the application. 6259a1de308cea2d160778fd977825f10a07b49d738Adam Powell * The MediaRouter will manage and dispatch events for user routes, but the application 6269a1de308cea2d160778fd977825f10a07b49d738Adam Powell * is expected to interpret the meaning of these events and perform the requested 6279a1de308cea2d160778fd977825f10a07b49d738Adam Powell * routing tasks.</p> 6289a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 62969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public static final int ROUTE_TYPE_USER = 1 << 23; 63069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 63169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown static final int ROUTE_TYPE_ANY = ROUTE_TYPE_LIVE_AUDIO | ROUTE_TYPE_LIVE_VIDEO 63269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown | ROUTE_TYPE_REMOTE_DISPLAY | ROUTE_TYPE_USER; 6339a1de308cea2d160778fd977825f10a07b49d738Adam Powell 63466f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown /** 63566f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * Flag for {@link #addCallback}: Actively scan for routes while this callback 63666f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * is registered. 63766f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * <p> 63866f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * When this flag is specified, the media router will actively scan for new 63966f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * routes. Certain routes, such as wifi display routes, may not be discoverable 64066f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * except when actively scanning. This flag is typically used when the route picker 64166f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * dialog has been opened by the user to ensure that the route information is 64266f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * up to date. 64366f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * </p><p> 64466f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * Active scanning may consume a significant amount of power and may have intrusive 64566f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * effects on wireless connectivity. Therefore it is important that active scanning 64666f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * only be requested when it is actually needed to satisfy a user request to 64766f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * discover and select a new route. 64866f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * </p> 64966f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown */ 65014507e257af5d71577574e25cbd690c4b54c9272Jeff Brown public static final int CALLBACK_FLAG_PERFORM_ACTIVE_SCAN = 1 << 0; 65166f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown 65266f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown /** 65366f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * Flag for {@link #addCallback}: Do not filter route events. 65466f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * <p> 65566f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * When this flag is specified, the callback will be invoked for event that affect any 65669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * route even if they do not match the callback's filter. 65766f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * </p> 65866f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown */ 65966f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown public static final int CALLBACK_FLAG_UNFILTERED_EVENTS = 1 << 1; 66066f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown 66169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown /** 66269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * Explicitly requests discovery. 66369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * 66469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * @hide Future API ported from support library. Revisit this later. 66569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown */ 66669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public static final int CALLBACK_FLAG_REQUEST_DISCOVERY = 1 << 2; 66769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 66869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown /** 66969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * Requests that discovery be performed but only if there is some other active 67069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * callback already registered. 67169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * 67269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * @hide Compatibility workaround for the fact that applications do not currently 67369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * request discovery explicitly (except when using the support library API). 67469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown */ 67569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public static final int CALLBACK_FLAG_PASSIVE_DISCOVERY = 1 << 3; 67669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 6770abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown /** 6780abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * Flag for {@link #isRouteAvailable}: Ignore the default route. 6790abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * <p> 6800abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * This flag is used to determine whether a matching non-default route is available. 6810abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * This constraint may be used to decide whether to offer the route chooser dialog 6820abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * to the user. There is no point offering the chooser if there are no 6830abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * non-default choices. 6840abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * </p> 6850abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * 6860abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * @hide Future API ported from support library. Revisit this later. 6870abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown */ 6880abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown public static final int AVAILABILITY_FLAG_IGNORE_DEFAULT_ROUTE = 1 << 0; 6890abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown 6909a1de308cea2d160778fd977825f10a07b49d738Adam Powell // Maps application contexts 6919a1de308cea2d160778fd977825f10a07b49d738Adam Powell static final HashMap<Context, MediaRouter> sRouters = new HashMap<Context, MediaRouter>(); 6929a1de308cea2d160778fd977825f10a07b49d738Adam Powell 6939a1de308cea2d160778fd977825f10a07b49d738Adam Powell static String typesToString(int types) { 6949a1de308cea2d160778fd977825f10a07b49d738Adam Powell final StringBuilder result = new StringBuilder(); 6959a1de308cea2d160778fd977825f10a07b49d738Adam Powell if ((types & ROUTE_TYPE_LIVE_AUDIO) != 0) { 6969a1de308cea2d160778fd977825f10a07b49d738Adam Powell result.append("ROUTE_TYPE_LIVE_AUDIO "); 6979a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 6982bb7c122ef6ce8539dfbaeb3292adcd942185f82Bryan Mawhinney if ((types & ROUTE_TYPE_LIVE_VIDEO) != 0) { 6992bb7c122ef6ce8539dfbaeb3292adcd942185f82Bryan Mawhinney result.append("ROUTE_TYPE_LIVE_VIDEO "); 7002bb7c122ef6ce8539dfbaeb3292adcd942185f82Bryan Mawhinney } 70169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if ((types & ROUTE_TYPE_REMOTE_DISPLAY) != 0) { 70269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown result.append("ROUTE_TYPE_REMOTE_DISPLAY "); 70369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 7049a1de308cea2d160778fd977825f10a07b49d738Adam Powell if ((types & ROUTE_TYPE_USER) != 0) { 7059a1de308cea2d160778fd977825f10a07b49d738Adam Powell result.append("ROUTE_TYPE_USER "); 7069a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 7079a1de308cea2d160778fd977825f10a07b49d738Adam Powell return result.toString(); 7089a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 7099a1de308cea2d160778fd977825f10a07b49d738Adam Powell 710b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn /** @hide */ 711b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn public MediaRouter(Context context) { 712b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn synchronized (Static.class) { 713b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn if (sStatic == null) { 7148e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final Context appContext = context.getApplicationContext(); 7158e37a85bf3dc39519942698dc90a3951306b934bAdam Powell sStatic = new Static(appContext); 7168e37a85bf3dc39519942698dc90a3951306b934bAdam Powell sStatic.startMonitoringRoutes(appContext); 717b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn } 7189a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 7199a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 7209a1de308cea2d160778fd977825f10a07b49d738Adam Powell 721690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell /** 7223afc18af2cea898753b10e8575dcf20c11356bcaJeff Brown * Gets the default route for playing media content on the system. 7233afc18af2cea898753b10e8575dcf20c11356bcaJeff Brown * <p> 7243afc18af2cea898753b10e8575dcf20c11356bcaJeff Brown * The system always provides a default route. 7253afc18af2cea898753b10e8575dcf20c11356bcaJeff Brown * </p> 7263afc18af2cea898753b10e8575dcf20c11356bcaJeff Brown * 7273afc18af2cea898753b10e8575dcf20c11356bcaJeff Brown * @return The default route, which is guaranteed to never be null. 728690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell */ 7293afc18af2cea898753b10e8575dcf20c11356bcaJeff Brown public RouteInfo getDefaultRoute() { 730705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell return sStatic.mDefaultAudioVideo; 731690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell } 732690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell 733690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell /** 7344599696591f745b3a546197d2ba7e5cfc5562484Adam Powell * @hide for use by framework routing UI 7354599696591f745b3a546197d2ba7e5cfc5562484Adam Powell */ 7363afc18af2cea898753b10e8575dcf20c11356bcaJeff Brown public RouteCategory getSystemCategory() { 7374599696591f745b3a546197d2ba7e5cfc5562484Adam Powell return sStatic.mSystemCategory; 7384599696591f745b3a546197d2ba7e5cfc5562484Adam Powell } 7394599696591f745b3a546197d2ba7e5cfc5562484Adam Powell 7400abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown /** @hide */ 7410abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown public RouteInfo getSelectedRoute() { 7420abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown return getSelectedRoute(ROUTE_TYPE_ANY); 7430abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown } 7440abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown 7454599696591f745b3a546197d2ba7e5cfc5562484Adam Powell /** 7461cf2ca83584a4cf0aa3ded787bd191b9a60e3521Adam Powell * Return the currently selected route for any of the given types 747690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell * 748690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell * @param type route types 749690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell * @return the selected route 750690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell */ 751690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell public RouteInfo getSelectedRoute(int type) { 7521cf2ca83584a4cf0aa3ded787bd191b9a60e3521Adam Powell if (sStatic.mSelectedRoute != null && 7531cf2ca83584a4cf0aa3ded787bd191b9a60e3521Adam Powell (sStatic.mSelectedRoute.mSupportedTypes & type) != 0) { 7541cf2ca83584a4cf0aa3ded787bd191b9a60e3521Adam Powell // If the selected route supports any of the types supplied, it's still considered 7551cf2ca83584a4cf0aa3ded787bd191b9a60e3521Adam Powell // 'selected' for that type. 7561cf2ca83584a4cf0aa3ded787bd191b9a60e3521Adam Powell return sStatic.mSelectedRoute; 7571cf2ca83584a4cf0aa3ded787bd191b9a60e3521Adam Powell } else if (type == ROUTE_TYPE_USER) { 7581cf2ca83584a4cf0aa3ded787bd191b9a60e3521Adam Powell // The caller specifically asked for a user route and the currently selected route 7591cf2ca83584a4cf0aa3ded787bd191b9a60e3521Adam Powell // doesn't qualify. 7601cf2ca83584a4cf0aa3ded787bd191b9a60e3521Adam Powell return null; 7611cf2ca83584a4cf0aa3ded787bd191b9a60e3521Adam Powell } 7621cf2ca83584a4cf0aa3ded787bd191b9a60e3521Adam Powell // If the above didn't match and we're not specifically asking for a user route, 7631cf2ca83584a4cf0aa3ded787bd191b9a60e3521Adam Powell // consider the default selected. 7641cf2ca83584a4cf0aa3ded787bd191b9a60e3521Adam Powell return sStatic.mDefaultAudioVideo; 765690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell } 766690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell 7679a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 7680abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * Returns true if there is a route that matches the specified types. 7690abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * <p> 7700abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * This method returns true if there are any available routes that match the types 7710abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * regardless of whether they are enabled or disabled. If the 7720abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * {@link #AVAILABILITY_FLAG_IGNORE_DEFAULT_ROUTE} flag is specified, then 7730abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * the method will only consider non-default routes. 7740abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * </p> 7750abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * 7760abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * @param types The types to match. 7770abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * @param flags Flags to control the determination of whether a route may be available. 7780abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * May be zero or {@link #AVAILABILITY_FLAG_IGNORE_DEFAULT_ROUTE}. 7790abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * @return True if a matching route may be available. 7800abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * 7810abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * @hide Future API ported from support library. Revisit this later. 7820abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown */ 7830abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown public boolean isRouteAvailable(int types, int flags) { 7840abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown final int count = sStatic.mRoutes.size(); 7850abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown for (int i = 0; i < count; i++) { 7860abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown RouteInfo route = sStatic.mRoutes.get(i); 7870abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown if (route.matchesTypes(types)) { 7880abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown if ((flags & AVAILABILITY_FLAG_IGNORE_DEFAULT_ROUTE) == 0 7890abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown || route != sStatic.mDefaultAudioVideo) { 7900abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown return true; 7910abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown } 7920abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown } 7930abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown } 7940abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown 7950abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown // It doesn't look like we can find a matching route right now. 7960abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown return false; 7970abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown } 7980abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown 7990abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown /** 8009a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Add a callback to listen to events about specific kinds of media routes. 8019a1de308cea2d160778fd977825f10a07b49d738Adam Powell * If the specified callback is already registered, its registration will be updated for any 8029a1de308cea2d160778fd977825f10a07b49d738Adam Powell * additional route types specified. 80366f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * <p> 80466f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * This is a convenience method that has the same effect as calling 80566f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * {@link #addCallback(int, Callback, int)} without flags. 80666f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * </p> 8079a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 8089a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param types Types of routes this callback is interested in 8099a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param cb Callback to add 8109a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 8119a1de308cea2d160778fd977825f10a07b49d738Adam Powell public void addCallback(int types, Callback cb) { 81266f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown addCallback(types, cb, 0); 81366f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown } 81466f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown 81566f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown /** 81666f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * Add a callback to listen to events about specific kinds of media routes. 81766f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * If the specified callback is already registered, its registration will be updated for any 81866f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * additional route types specified. 81966f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * <p> 82066f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * By default, the callback will only be invoked for events that affect routes 82166f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * that match the specified selector. The filtering may be disabled by specifying 82266f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * the {@link #CALLBACK_FLAG_UNFILTERED_EVENTS} flag. 82366f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * </p> 82466f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * 82566f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * @param types Types of routes this callback is interested in 82666f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * @param cb Callback to add 82766f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * @param flags Flags to control the behavior of the callback. 82814507e257af5d71577574e25cbd690c4b54c9272Jeff Brown * May be zero or a combination of {@link #CALLBACK_FLAG_PERFORM_ACTIVE_SCAN} and 82966f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * {@link #CALLBACK_FLAG_UNFILTERED_EVENTS}. 83066f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown */ 83166f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown public void addCallback(int types, Callback cb, int flags) { 83266f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown CallbackInfo info; 83366f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown int index = findCallbackInfo(cb); 83466f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown if (index >= 0) { 83566f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown info = sStatic.mCallbacks.get(index); 83666f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown info.type |= types; 83766f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown info.flags |= flags; 83866f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown } else { 83966f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown info = new CallbackInfo(cb, types, flags, this); 84066f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown sStatic.mCallbacks.add(info); 84166f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown } 84269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown sStatic.updateDiscoveryRequest(); 8439a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 8449a1de308cea2d160778fd977825f10a07b49d738Adam Powell 8459a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 8469a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Remove the specified callback. It will no longer receive events about media routing. 8479a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 8489a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param cb Callback to remove 8499a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 8509a1de308cea2d160778fd977825f10a07b49d738Adam Powell public void removeCallback(Callback cb) { 85166f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown int index = findCallbackInfo(cb); 85266f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown if (index >= 0) { 85369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown sStatic.mCallbacks.remove(index); 85469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown sStatic.updateDiscoveryRequest(); 85566f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown } else { 85666f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown Log.w(TAG, "removeCallback(" + cb + "): callback not registered"); 85766f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown } 85866f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown } 85966f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown 86066f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown private int findCallbackInfo(Callback cb) { 861b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn final int count = sStatic.mCallbacks.size(); 8629a1de308cea2d160778fd977825f10a07b49d738Adam Powell for (int i = 0; i < count; i++) { 86366f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown final CallbackInfo info = sStatic.mCallbacks.get(i); 86466f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown if (info.cb == cb) { 86566f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown return i; 8669a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 8679a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 86866f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown return -1; 8699a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 8709a1de308cea2d160778fd977825f10a07b49d738Adam Powell 871d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell /** 872d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * Select the specified route to use for output of the given media types. 8733afc18af2cea898753b10e8575dcf20c11356bcaJeff Brown * <p class="note"> 8743afc18af2cea898753b10e8575dcf20c11356bcaJeff Brown * As API version 18, this function may be used to select any route. 8753afc18af2cea898753b10e8575dcf20c11356bcaJeff Brown * In prior versions, this function could only be used to select user 8763afc18af2cea898753b10e8575dcf20c11356bcaJeff Brown * routes and would ignore any attempt to select a system route. 8773afc18af2cea898753b10e8575dcf20c11356bcaJeff Brown * </p> 878d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * 879d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param types type flags indicating which types this route should be used for. 880d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * The route must support at least a subset. 881d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param route Route to select 882d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell */ 8839a1de308cea2d160778fd977825f10a07b49d738Adam Powell public void selectRoute(int types, RouteInfo route) { 88469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown selectRouteStatic(types, route, true); 8850d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell } 88669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 8870d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell /** 8880d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * @hide internal use 8890d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell */ 89069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public void selectRouteInt(int types, RouteInfo route, boolean explicit) { 89169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown selectRouteStatic(types, route, explicit); 892b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn } 893b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn 89469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown static void selectRouteStatic(int types, RouteInfo route, boolean explicit) { 895705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell final RouteInfo oldRoute = sStatic.mSelectedRoute; 896705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell if (oldRoute == route) return; 8970abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown if (!route.matchesTypes(types)) { 8980d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell Log.w(TAG, "selectRoute ignored; cannot select route with supported types " + 8990d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell typesToString(route.getSupportedTypes()) + " into route types " + 9000d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell typesToString(types)); 9014ee1f55ce0f4909a7430ab44563a81852f335071Adam Powell return; 9020d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell } 9039a1de308cea2d160778fd977825f10a07b49d738Adam Powell 904dd0a19266d5c837069da1ea188744d54c8d723a8Adam Powell final RouteInfo btRoute = sStatic.mBluetoothA2dpRoute; 905dd0a19266d5c837069da1ea188744d54c8d723a8Adam Powell if (btRoute != null && (types & ROUTE_TYPE_LIVE_AUDIO) != 0 && 906705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell (route == btRoute || route == sStatic.mDefaultAudioVideo)) { 907dd0a19266d5c837069da1ea188744d54c8d723a8Adam Powell try { 908dd0a19266d5c837069da1ea188744d54c8d723a8Adam Powell sStatic.mAudioService.setBluetoothA2dpOn(route == btRoute); 909dd0a19266d5c837069da1ea188744d54c8d723a8Adam Powell } catch (RemoteException e) { 910dd0a19266d5c837069da1ea188744d54c8d723a8Adam Powell Log.e(TAG, "Error changing Bluetooth A2DP state", e); 911dd0a19266d5c837069da1ea188744d54c8d723a8Adam Powell } 912dd0a19266d5c837069da1ea188744d54c8d723a8Adam Powell } 913dd0a19266d5c837069da1ea188744d54c8d723a8Adam Powell 914705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell final WifiDisplay activeDisplay = 915705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell sStatic.mDisplayService.getWifiDisplayStatus().getActiveDisplay(); 916705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell final boolean oldRouteHasAddress = oldRoute != null && oldRoute.mDeviceAddress != null; 917705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell final boolean newRouteHasAddress = route != null && route.mDeviceAddress != null; 918705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell if (activeDisplay != null || oldRouteHasAddress || newRouteHasAddress) { 919705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell if (newRouteHasAddress && !matchesDeviceAddress(activeDisplay, route)) { 920af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown if (sStatic.mCanConfigureWifiDisplays) { 921af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown sStatic.mDisplayService.connectWifiDisplay(route.mDeviceAddress); 922af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown } else { 923af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown Log.e(TAG, "Cannot connect to wifi displays because this process " 924af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown + "is not allowed to do so."); 925af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown } 926705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } else if (activeDisplay != null && !newRouteHasAddress) { 927705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell sStatic.mDisplayService.disconnectWifiDisplay(); 928705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 929705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 930705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 93169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown sStatic.setSelectedRoute(route, explicit); 93269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 933705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell if (oldRoute != null) { 934705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell dispatchRouteUnselected(types & oldRoute.getSupportedTypes(), oldRoute); 93539ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown if (oldRoute.resolveStatusCode()) { 93639ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown dispatchRouteChanged(oldRoute); 93739ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown } 9389a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 9399a1de308cea2d160778fd977825f10a07b49d738Adam Powell if (route != null) { 94039ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown if (route.resolveStatusCode()) { 94139ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown dispatchRouteChanged(route); 94239ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown } 9439a1de308cea2d160778fd977825f10a07b49d738Adam Powell dispatchRouteSelected(types & route.getSupportedTypes(), route); 9449a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 945ce468a35b388ca46578934706b38dbae94941643Jeff Brown 946ce468a35b388ca46578934706b38dbae94941643Jeff Brown // The behavior of active scans may depend on the currently selected route. 947ce468a35b388ca46578934706b38dbae94941643Jeff Brown sStatic.updateDiscoveryRequest(); 9489a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 9499a1de308cea2d160778fd977825f10a07b49d738Adam Powell 95069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown static void selectDefaultRouteStatic() { 95169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // TODO: Be smarter about the route types here; this selects for all valid. 95269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (sStatic.mSelectedRoute != sStatic.mBluetoothA2dpRoute 95369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown && sStatic.mBluetoothA2dpRoute != null) { 95469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown selectRouteStatic(ROUTE_TYPE_ANY, sStatic.mBluetoothA2dpRoute, false); 95569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } else { 95669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown selectRouteStatic(ROUTE_TYPE_ANY, sStatic.mDefaultAudioVideo, false); 95769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 95869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 95969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 9609a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 961705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell * Compare the device address of a display and a route. 962705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell * Nulls/no device address will match another null/no address. 963705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell */ 964705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell static boolean matchesDeviceAddress(WifiDisplay display, RouteInfo info) { 965705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell final boolean routeHasAddress = info != null && info.mDeviceAddress != null; 966705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell if (display == null && !routeHasAddress) { 967705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell return true; 968705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 969705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 970705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell if (display != null && routeHasAddress) { 971705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell return display.getDeviceAddress().equals(info.mDeviceAddress); 972705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 973705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell return false; 974705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 975705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 976705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell /** 9779a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Add an app-specified route for media to the MediaRouter. 9789a1de308cea2d160778fd977825f10a07b49d738Adam Powell * App-specified route definitions are created using {@link #createUserRoute(RouteCategory)} 9799a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 9809a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param info Definition of the route to add 9813afc18af2cea898753b10e8575dcf20c11356bcaJeff Brown * @see #createUserRoute(RouteCategory) 9829a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @see #removeUserRoute(UserRouteInfo) 9839a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 9849a1de308cea2d160778fd977825f10a07b49d738Adam Powell public void addUserRoute(UserRouteInfo info) { 9852ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell addRouteStatic(info); 9869a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 9879a1de308cea2d160778fd977825f10a07b49d738Adam Powell 988d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell /** 989d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell * @hide Framework use only 990d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell */ 991d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell public void addRouteInt(RouteInfo info) { 9922ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell addRouteStatic(info); 993d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell } 994d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell 9952ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell static void addRouteStatic(RouteInfo info) { 9969a1de308cea2d160778fd977825f10a07b49d738Adam Powell final RouteCategory cat = info.getCategory(); 997b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn if (!sStatic.mCategories.contains(cat)) { 998b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn sStatic.mCategories.add(cat); 9999a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 1000d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell if (cat.isGroupable() && !(info instanceof RouteGroup)) { 10019a1de308cea2d160778fd977825f10a07b49d738Adam Powell // Enforce that any added route in a groupable category must be in a group. 10029a1de308cea2d160778fd977825f10a07b49d738Adam Powell final RouteGroup group = new RouteGroup(info.getCategory()); 1003dbbfa702a09f6d2d36dee1b552442d04a4673f89Adam Powell group.mSupportedTypes = info.mSupportedTypes; 1004b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn sStatic.mRoutes.add(group); 1005d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell dispatchRouteAdded(group); 1006b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell group.addRoute(info); 1007d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell 10089a1de308cea2d160778fd977825f10a07b49d738Adam Powell info = group; 1009d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell } else { 1010b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn sStatic.mRoutes.add(info); 1011d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell dispatchRouteAdded(info); 10129a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 10139a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 10149a1de308cea2d160778fd977825f10a07b49d738Adam Powell 10159a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 10169a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Remove an app-specified route for media from the MediaRouter. 10179a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 10189a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param info Definition of the route to remove 10199a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @see #addUserRoute(UserRouteInfo) 10209a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 10219a1de308cea2d160778fd977825f10a07b49d738Adam Powell public void removeUserRoute(UserRouteInfo info) { 102269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown removeRouteStatic(info); 10239a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 10249a1de308cea2d160778fd977825f10a07b49d738Adam Powell 1025690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell /** 1026690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell * Remove all app-specified routes from the MediaRouter. 1027690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell * 1028690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell * @see #removeUserRoute(UserRouteInfo) 1029690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell */ 1030690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell public void clearUserRoutes() { 1031b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn for (int i = 0; i < sStatic.mRoutes.size(); i++) { 1032b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn final RouteInfo info = sStatic.mRoutes.get(i); 1033d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell // TODO Right now, RouteGroups only ever contain user routes. 1034d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell // The code below will need to change if this assumption does. 1035d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell if (info instanceof UserRouteInfo || info instanceof RouteGroup) { 103669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown removeRouteStatic(info); 1037690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell i--; 1038690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell } 1039690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell } 1040690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell } 1041690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell 1042d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell /** 1043d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell * @hide internal use only 1044d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell */ 1045d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell public void removeRouteInt(RouteInfo info) { 104669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown removeRouteStatic(info); 1047d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell } 1048d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell 104969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown static void removeRouteStatic(RouteInfo info) { 1050b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn if (sStatic.mRoutes.remove(info)) { 10519a1de308cea2d160778fd977825f10a07b49d738Adam Powell final RouteCategory removingCat = info.getCategory(); 1052b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn final int count = sStatic.mRoutes.size(); 10539a1de308cea2d160778fd977825f10a07b49d738Adam Powell boolean found = false; 10549a1de308cea2d160778fd977825f10a07b49d738Adam Powell for (int i = 0; i < count; i++) { 1055b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn final RouteCategory cat = sStatic.mRoutes.get(i).getCategory(); 10569a1de308cea2d160778fd977825f10a07b49d738Adam Powell if (removingCat == cat) { 10579a1de308cea2d160778fd977825f10a07b49d738Adam Powell found = true; 10589a1de308cea2d160778fd977825f10a07b49d738Adam Powell break; 10599a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 10609a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 10610abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown if (info.isSelected()) { 1062d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell // Removing the currently selected route? Select the default before we remove it. 106369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown selectDefaultRouteStatic(); 1064d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell } 1065690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell if (!found) { 1066b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn sStatic.mCategories.remove(removingCat); 1067690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell } 1068690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell dispatchRouteRemoved(info); 1069690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell } 1070690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell } 1071690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell 10729a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 10739a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Return the number of {@link MediaRouter.RouteCategory categories} currently 10749a1de308cea2d160778fd977825f10a07b49d738Adam Powell * represented by routes known to this MediaRouter. 10759a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 10769a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @return the number of unique categories represented by this MediaRouter's known routes 10779a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 10789a1de308cea2d160778fd977825f10a07b49d738Adam Powell public int getCategoryCount() { 1079b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn return sStatic.mCategories.size(); 10809a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 10819a1de308cea2d160778fd977825f10a07b49d738Adam Powell 10829a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 10839a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Return the {@link MediaRouter.RouteCategory category} at the given index. 10849a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Valid indices are in the range [0-getCategoryCount). 10859a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 10869a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param index which category to return 10879a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @return the category at index 10889a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 10899a1de308cea2d160778fd977825f10a07b49d738Adam Powell public RouteCategory getCategoryAt(int index) { 1090b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn return sStatic.mCategories.get(index); 10919a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 10929a1de308cea2d160778fd977825f10a07b49d738Adam Powell 10939a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 10949a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Return the number of {@link MediaRouter.RouteInfo routes} currently known 10959a1de308cea2d160778fd977825f10a07b49d738Adam Powell * to this MediaRouter. 10969a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 10979a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @return the number of routes tracked by this router 10989a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 10999a1de308cea2d160778fd977825f10a07b49d738Adam Powell public int getRouteCount() { 1100b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn return sStatic.mRoutes.size(); 11019a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 11029a1de308cea2d160778fd977825f10a07b49d738Adam Powell 11039a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 11049a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Return the route at the specified index. 11059a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 11069a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param index index of the route to return 11079a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @return the route at index 11089a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 11099a1de308cea2d160778fd977825f10a07b49d738Adam Powell public RouteInfo getRouteAt(int index) { 1110b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn return sStatic.mRoutes.get(index); 1111b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn } 1112b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn 1113b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn static int getRouteCountStatic() { 1114b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn return sStatic.mRoutes.size(); 1115b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn } 1116b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn 1117b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn static RouteInfo getRouteAtStatic(int index) { 1118b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn return sStatic.mRoutes.get(index); 11199a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 11209a1de308cea2d160778fd977825f10a07b49d738Adam Powell 11219a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 11229a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Create a new user route that may be modified and registered for use by the application. 11239a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 11249a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param category The category the new route will belong to 11259a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @return A new UserRouteInfo for use by the application 11269a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 11279a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @see #addUserRoute(UserRouteInfo) 11289a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @see #removeUserRoute(UserRouteInfo) 112969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * @see #createRouteCategory(CharSequence, boolean) 11309a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 11319a1de308cea2d160778fd977825f10a07b49d738Adam Powell public UserRouteInfo createUserRoute(RouteCategory category) { 11329a1de308cea2d160778fd977825f10a07b49d738Adam Powell return new UserRouteInfo(category); 11339a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 11349a1de308cea2d160778fd977825f10a07b49d738Adam Powell 11359a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 11369a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Create a new route category. Each route must belong to a category. 11379a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 11389a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param name Name of the new category 11399a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param isGroupable true if routes in this category may be grouped with one another 11409a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @return the new RouteCategory 11419a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 11429a1de308cea2d160778fd977825f10a07b49d738Adam Powell public RouteCategory createRouteCategory(CharSequence name, boolean isGroupable) { 11439a1de308cea2d160778fd977825f10a07b49d738Adam Powell return new RouteCategory(name, ROUTE_TYPE_USER, isGroupable); 11449a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 11455d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik 11460d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell /** 11470d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * Create a new route category. Each route must belong to a category. 11480d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * 11490d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * @param nameResId Resource ID of the name of the new category 11500d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * @param isGroupable true if routes in this category may be grouped with one another 11510d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * @return the new RouteCategory 11520d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell */ 11530d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public RouteCategory createRouteCategory(int nameResId, boolean isGroupable) { 11540d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell return new RouteCategory(nameResId, ROUTE_TYPE_USER, isGroupable); 11550d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell } 11569a1de308cea2d160778fd977825f10a07b49d738Adam Powell 115769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown /** 115869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * Rebinds the media router to handle routes that belong to the specified user. 115969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * Requires the interact across users permission to access the routes of another user. 116069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * <p> 116169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * This method is a complete hack to work around the singleton nature of the 116269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * media router when running inside of singleton processes like QuickSettings. 116369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * This mechanism should be burned to the ground when MediaRouter is redesigned. 116469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * Ideally the current user would be pulled from the Context but we need to break 116569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * down MediaRouter.Static before we can get there. 116669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * </p> 116769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * 116869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * @hide 116969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown */ 117069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public void rebindAsUser(int userId) { 117169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown sStatic.rebindAsUser(userId); 117269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 117369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 1174b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn static void updateRoute(final RouteInfo info) { 11759a1de308cea2d160778fd977825f10a07b49d738Adam Powell dispatchRouteChanged(info); 11769a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 11779a1de308cea2d160778fd977825f10a07b49d738Adam Powell 1178b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn static void dispatchRouteSelected(int type, RouteInfo info) { 117939d5c6172503620ac3761148adac5fd7fa20d02dAdam Powell for (CallbackInfo cbi : sStatic.mCallbacks) { 118066f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown if (cbi.filterRouteEvent(info)) { 1181b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn cbi.cb.onRouteSelected(cbi.router, type, info); 11829a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 11839a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 11849a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 11859a1de308cea2d160778fd977825f10a07b49d738Adam Powell 1186b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn static void dispatchRouteUnselected(int type, RouteInfo info) { 118739d5c6172503620ac3761148adac5fd7fa20d02dAdam Powell for (CallbackInfo cbi : sStatic.mCallbacks) { 118866f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown if (cbi.filterRouteEvent(info)) { 1189b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn cbi.cb.onRouteUnselected(cbi.router, type, info); 11909a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 11919a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 11929a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 11939a1de308cea2d160778fd977825f10a07b49d738Adam Powell 1194b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn static void dispatchRouteChanged(RouteInfo info) { 1195af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown dispatchRouteChanged(info, info.mSupportedTypes); 1196af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown } 1197af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown 1198af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown static void dispatchRouteChanged(RouteInfo info, int oldSupportedTypes) { 1199af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown final int newSupportedTypes = info.mSupportedTypes; 120039d5c6172503620ac3761148adac5fd7fa20d02dAdam Powell for (CallbackInfo cbi : sStatic.mCallbacks) { 1201af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown // Reconstruct some of the history for callbacks that may not have observed 1202af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown // all of the events needed to correctly interpret the current state. 1203af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown // FIXME: This is a strong signal that we should deprecate route type filtering 1204af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown // completely in the future because it can lead to inconsistencies in 1205af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown // applications. 1206af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown final boolean oldVisibility = cbi.filterRouteEvent(oldSupportedTypes); 1207af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown final boolean newVisibility = cbi.filterRouteEvent(newSupportedTypes); 1208af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown if (!oldVisibility && newVisibility) { 1209af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown cbi.cb.onRouteAdded(cbi.router, info); 1210af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown if (info.isSelected()) { 1211af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown cbi.cb.onRouteSelected(cbi.router, newSupportedTypes, info); 1212af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown } 1213af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown } 1214af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown if (oldVisibility || newVisibility) { 1215b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn cbi.cb.onRouteChanged(cbi.router, info); 12169a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 1217af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown if (oldVisibility && !newVisibility) { 1218af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown if (info.isSelected()) { 1219af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown cbi.cb.onRouteUnselected(cbi.router, oldSupportedTypes, info); 1220af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown } 1221af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown cbi.cb.onRouteRemoved(cbi.router, info); 1222af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown } 12239a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 12249a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 12259a1de308cea2d160778fd977825f10a07b49d738Adam Powell 1226b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn static void dispatchRouteAdded(RouteInfo info) { 122739d5c6172503620ac3761148adac5fd7fa20d02dAdam Powell for (CallbackInfo cbi : sStatic.mCallbacks) { 122866f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown if (cbi.filterRouteEvent(info)) { 1229b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn cbi.cb.onRouteAdded(cbi.router, info); 12309a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 12319a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 12329a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 12339a1de308cea2d160778fd977825f10a07b49d738Adam Powell 1234b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn static void dispatchRouteRemoved(RouteInfo info) { 123539d5c6172503620ac3761148adac5fd7fa20d02dAdam Powell for (CallbackInfo cbi : sStatic.mCallbacks) { 123666f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown if (cbi.filterRouteEvent(info)) { 1237b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn cbi.cb.onRouteRemoved(cbi.router, info); 12389a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 12399a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 12409a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 12419a1de308cea2d160778fd977825f10a07b49d738Adam Powell 1242b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn static void dispatchRouteGrouped(RouteInfo info, RouteGroup group, int index) { 124339d5c6172503620ac3761148adac5fd7fa20d02dAdam Powell for (CallbackInfo cbi : sStatic.mCallbacks) { 124466f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown if (cbi.filterRouteEvent(group)) { 1245b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn cbi.cb.onRouteGrouped(cbi.router, info, group, index); 1246d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell } 1247d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell } 1248d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell } 1249d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell 1250b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn static void dispatchRouteUngrouped(RouteInfo info, RouteGroup group) { 125139d5c6172503620ac3761148adac5fd7fa20d02dAdam Powell for (CallbackInfo cbi : sStatic.mCallbacks) { 125266f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown if (cbi.filterRouteEvent(group)) { 1253b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn cbi.cb.onRouteUngrouped(cbi.router, info, group); 12549a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 12559a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 12569a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 12579a1de308cea2d160778fd977825f10a07b49d738Adam Powell 12588e37a85bf3dc39519942698dc90a3951306b934bAdam Powell static void dispatchRouteVolumeChanged(RouteInfo info) { 12598e37a85bf3dc39519942698dc90a3951306b934bAdam Powell for (CallbackInfo cbi : sStatic.mCallbacks) { 126066f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown if (cbi.filterRouteEvent(info)) { 12618e37a85bf3dc39519942698dc90a3951306b934bAdam Powell cbi.cb.onRouteVolumeChanged(cbi.router, info); 12628e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 12638e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 12648e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 12658e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 126692130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown static void dispatchRoutePresentationDisplayChanged(RouteInfo info) { 126792130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown for (CallbackInfo cbi : sStatic.mCallbacks) { 126866f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown if (cbi.filterRouteEvent(info)) { 126992130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown cbi.cb.onRoutePresentationDisplayChanged(cbi.router, info); 127092130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown } 127192130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown } 127292130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown } 127392130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown 12748e37a85bf3dc39519942698dc90a3951306b934bAdam Powell static void systemVolumeChanged(int newValue) { 12758e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final RouteInfo selectedRoute = sStatic.mSelectedRoute; 12768e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (selectedRoute == null) return; 12778e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 12788e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (selectedRoute == sStatic.mBluetoothA2dpRoute || 1279705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell selectedRoute == sStatic.mDefaultAudioVideo) { 12808e37a85bf3dc39519942698dc90a3951306b934bAdam Powell dispatchRouteVolumeChanged(selectedRoute); 12818e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } else if (sStatic.mBluetoothA2dpRoute != null) { 12828e37a85bf3dc39519942698dc90a3951306b934bAdam Powell try { 12838e37a85bf3dc39519942698dc90a3951306b934bAdam Powell dispatchRouteVolumeChanged(sStatic.mAudioService.isBluetoothA2dpOn() ? 1284705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell sStatic.mBluetoothA2dpRoute : sStatic.mDefaultAudioVideo); 12858e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } catch (RemoteException e) { 12868e37a85bf3dc39519942698dc90a3951306b934bAdam Powell Log.e(TAG, "Error checking Bluetooth A2DP state to report volume change", e); 12878e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 12888e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } else { 1289705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell dispatchRouteVolumeChanged(sStatic.mDefaultAudioVideo); 1290705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1291705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1292705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 129375af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown static void updateWifiDisplayStatus(WifiDisplayStatus status) { 129475af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown WifiDisplay[] displays; 1295615e413a90ff5898d8c458ebc9649ca95fa9fd98Adam Powell WifiDisplay activeDisplay; 129675af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown if (status.getFeatureState() == WifiDisplayStatus.FEATURE_STATE_ON) { 129775af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown displays = status.getDisplays(); 129875af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown activeDisplay = status.getActiveDisplay(); 1299af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown 1300af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown // Only the system is able to connect to wifi display routes. 1301af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown // The display manager will enforce this with a permission check but it 1302af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown // still publishes information about all available displays. 1303af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown // Filter the list down to just the active display. 1304af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown if (!sStatic.mCanConfigureWifiDisplays) { 1305af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown if (activeDisplay != null) { 1306af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown displays = new WifiDisplay[] { activeDisplay }; 1307af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown } else { 1308af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown displays = WifiDisplay.EMPTY_ARRAY; 1309af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown } 1310af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown } 1311615e413a90ff5898d8c458ebc9649ca95fa9fd98Adam Powell } else { 131275af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown displays = WifiDisplay.EMPTY_ARRAY; 1313615e413a90ff5898d8c458ebc9649ca95fa9fd98Adam Powell activeDisplay = null; 1314615e413a90ff5898d8c458ebc9649ca95fa9fd98Adam Powell } 1315ce468a35b388ca46578934706b38dbae94941643Jeff Brown String activeDisplayAddress = activeDisplay != null ? 1316ce468a35b388ca46578934706b38dbae94941643Jeff Brown activeDisplay.getDeviceAddress() : null; 1317705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 131875af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown // Add or update routes. 131975af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown for (int i = 0; i < displays.length; i++) { 132075af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown final WifiDisplay d = displays[i]; 132175af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown if (shouldShowWifiDisplay(d, activeDisplay)) { 1322ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang RouteInfo route = findWifiDisplayRoute(d); 1323ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang if (route == null) { 132475af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown route = makeWifiDisplayRoute(d, status); 1325ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang addRouteStatic(route); 1326ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang } else { 1327ce468a35b388ca46578934706b38dbae94941643Jeff Brown String address = d.getDeviceAddress(); 1328ce468a35b388ca46578934706b38dbae94941643Jeff Brown boolean disconnected = !address.equals(activeDisplayAddress) 1329ce468a35b388ca46578934706b38dbae94941643Jeff Brown && address.equals(sStatic.mPreviousActiveWifiDisplayAddress); 1330ce468a35b388ca46578934706b38dbae94941643Jeff Brown updateWifiDisplayRoute(route, d, status, disconnected); 1331ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang } 1332ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang if (d.equals(activeDisplay)) { 133369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown selectRouteStatic(route.getSupportedTypes(), route, false); 1334ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang } 13352ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell } 1336705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 133775af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown 133875af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown // Remove stale routes. 133975af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown for (int i = sStatic.mRoutes.size(); i-- > 0; ) { 134075af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown RouteInfo route = sStatic.mRoutes.get(i); 134175af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown if (route.mDeviceAddress != null) { 134275af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown WifiDisplay d = findWifiDisplay(displays, route.mDeviceAddress); 134375af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown if (d == null || !shouldShowWifiDisplay(d, activeDisplay)) { 134475af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown removeRouteStatic(route); 1345ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang } 1346705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1347705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1348ce468a35b388ca46578934706b38dbae94941643Jeff Brown 1349ce468a35b388ca46578934706b38dbae94941643Jeff Brown // Remember the current active wifi display address so that we can infer disconnections. 1350ce468a35b388ca46578934706b38dbae94941643Jeff Brown // TODO: This hack will go away once all of this is moved into the media router service. 1351ce468a35b388ca46578934706b38dbae94941643Jeff Brown sStatic.mPreviousActiveWifiDisplayAddress = activeDisplayAddress; 135275af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown } 1353705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 135475af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown private static boolean shouldShowWifiDisplay(WifiDisplay d, WifiDisplay activeDisplay) { 135575af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown return d.isRemembered() || d.equals(activeDisplay); 1356705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1357705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 1358ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang static int getWifiDisplayStatusCode(WifiDisplay d, WifiDisplayStatus wfdStatus) { 135969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown int newStatus; 1360ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang if (wfdStatus.getScanState() == WifiDisplayStatus.SCAN_STATE_SCANNING) { 1361ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang newStatus = RouteInfo.STATUS_SCANNING; 1362ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang } else if (d.isAvailable()) { 1363ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang newStatus = d.canConnect() ? 1364ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang RouteInfo.STATUS_AVAILABLE: RouteInfo.STATUS_IN_USE; 1365705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } else { 1366705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell newStatus = RouteInfo.STATUS_NOT_AVAILABLE; 1367705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1368705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 1369ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang if (d.equals(wfdStatus.getActiveDisplay())) { 1370ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang final int activeState = wfdStatus.getActiveDisplayState(); 1371705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell switch (activeState) { 1372705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell case WifiDisplayStatus.DISPLAY_STATE_CONNECTED: 137369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown newStatus = RouteInfo.STATUS_CONNECTED; 1374705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell break; 1375705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell case WifiDisplayStatus.DISPLAY_STATE_CONNECTING: 1376705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell newStatus = RouteInfo.STATUS_CONNECTING; 1377705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell break; 1378705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell case WifiDisplayStatus.DISPLAY_STATE_NOT_CONNECTED: 1379705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell Log.e(TAG, "Active display is not connected!"); 1380705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell break; 1381705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1382705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1383705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 1384ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang return newStatus; 1385ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang } 1386ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang 1387ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang static boolean isWifiDisplayEnabled(WifiDisplay d, WifiDisplayStatus wfdStatus) { 1388ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang return d.isAvailable() && (d.canConnect() || d.equals(wfdStatus.getActiveDisplay())); 1389ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang } 1390ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang 1391ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang static RouteInfo makeWifiDisplayRoute(WifiDisplay display, WifiDisplayStatus wfdStatus) { 1392ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang final RouteInfo newRoute = new RouteInfo(sStatic.mSystemCategory); 1393ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang newRoute.mDeviceAddress = display.getDeviceAddress(); 139469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown newRoute.mSupportedTypes = ROUTE_TYPE_LIVE_AUDIO | ROUTE_TYPE_LIVE_VIDEO 139569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown | ROUTE_TYPE_REMOTE_DISPLAY; 1396ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang newRoute.mVolumeHandling = RouteInfo.PLAYBACK_VOLUME_FIXED; 1397ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang newRoute.mPlaybackType = RouteInfo.PLAYBACK_TYPE_REMOTE; 1398ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang 139939ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown newRoute.setRealStatusCode(getWifiDisplayStatusCode(display, wfdStatus)); 1400ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang newRoute.mEnabled = isWifiDisplayEnabled(display, wfdStatus); 1401ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang newRoute.mName = display.getFriendlyDisplayName(); 1402ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang newRoute.mDescription = sStatic.mResources.getText( 1403ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang com.android.internal.R.string.wireless_display_route_description); 14045830b0b33618940d65197cec99d697b21908fec8Chong Zhang newRoute.updatePresentationDisplay(); 1405ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang return newRoute; 1406ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang } 1407ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang 1408ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang private static void updateWifiDisplayRoute( 1409ce468a35b388ca46578934706b38dbae94941643Jeff Brown RouteInfo route, WifiDisplay display, WifiDisplayStatus wfdStatus, 1410ce468a35b388ca46578934706b38dbae94941643Jeff Brown boolean disconnected) { 1411ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang boolean changed = false; 14122444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown final String newName = display.getFriendlyDisplayName(); 14132444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown if (!route.getName().equals(newName)) { 1414705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell route.mName = newName; 1415705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell changed = true; 1416705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1417705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 1418ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang boolean enabled = isWifiDisplayEnabled(display, wfdStatus); 1419ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang changed |= route.mEnabled != enabled; 1420ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang route.mEnabled = enabled; 1421705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 142239ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown changed |= route.setRealStatusCode(getWifiDisplayStatusCode(display, wfdStatus)); 1423705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 1424705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell if (changed) { 1425705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell dispatchRouteChanged(route); 1426705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1427705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 1428ce468a35b388ca46578934706b38dbae94941643Jeff Brown if ((!enabled || disconnected) && route.isSelected()) { 1429705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell // Oops, no longer available. Reselect the default. 143069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown selectDefaultRouteStatic(); 1431705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1432705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1433705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 143475af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown private static WifiDisplay findWifiDisplay(WifiDisplay[] displays, String deviceAddress) { 1435705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell for (int i = 0; i < displays.length; i++) { 143675af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown final WifiDisplay d = displays[i]; 143775af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown if (d.getDeviceAddress().equals(deviceAddress)) { 143875af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown return d; 1439705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1440705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1441705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell return null; 1442705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1443705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 1444705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell private static RouteInfo findWifiDisplayRoute(WifiDisplay d) { 1445705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell final int count = sStatic.mRoutes.size(); 1446705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell for (int i = 0; i < count; i++) { 1447705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell final RouteInfo info = sStatic.mRoutes.get(i); 1448705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell if (d.getDeviceAddress().equals(info.mDeviceAddress)) { 1449705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell return info; 1450705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1451705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1452705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell return null; 14538e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 14548e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 14559a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 14569a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Information about a media route. 14579a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 1458b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn public static class RouteInfo { 14599a1de308cea2d160778fd977825f10a07b49d738Adam Powell CharSequence mName; 14600d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell int mNameResId; 146156d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown CharSequence mDescription; 14629a1de308cea2d160778fd977825f10a07b49d738Adam Powell private CharSequence mStatus; 14639a1de308cea2d160778fd977825f10a07b49d738Adam Powell int mSupportedTypes; 14649a1de308cea2d160778fd977825f10a07b49d738Adam Powell RouteGroup mGroup; 14659a1de308cea2d160778fd977825f10a07b49d738Adam Powell final RouteCategory mCategory; 1466ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell Drawable mIcon; 14671357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi // playback information 14681357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi int mPlaybackType = PLAYBACK_TYPE_LOCAL; 14691357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi int mVolumeMax = RemoteControlClient.DEFAULT_PLAYBACK_VOLUME; 14701357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi int mVolume = RemoteControlClient.DEFAULT_PLAYBACK_VOLUME; 14711357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi int mVolumeHandling = RemoteControlClient.DEFAULT_PLAYBACK_VOLUME_HANDLING; 14721357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi int mPlaybackStream = AudioManager.STREAM_MUSIC; 14731357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi VolumeCallbackInfo mVcb; 147492130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown Display mPresentationDisplay; 14755830b0b33618940d65197cec99d697b21908fec8Chong Zhang int mPresentationDisplayId = -1; 14769a1de308cea2d160778fd977825f10a07b49d738Adam Powell 1477705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell String mDeviceAddress; 1478705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell boolean mEnabled = true; 1479705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 148069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // An id by which the route is known to the media router service. 148169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Null if this route only exists as an artifact within this process. 148269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown String mGlobalRouteId; 148369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 1484705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell // A predetermined connection status that can override mStatus 148539ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown private int mRealStatusCode; 148639ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown private int mResolvedStatusCode; 1487705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 14882ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell /** @hide */ public static final int STATUS_NONE = 0; 14892ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell /** @hide */ public static final int STATUS_SCANNING = 1; 14902ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell /** @hide */ public static final int STATUS_CONNECTING = 2; 14912ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell /** @hide */ public static final int STATUS_AVAILABLE = 3; 14922ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell /** @hide */ public static final int STATUS_NOT_AVAILABLE = 4; 1493ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang /** @hide */ public static final int STATUS_IN_USE = 5; 149469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown /** @hide */ public static final int STATUS_CONNECTED = 6; 1495705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 1496b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell private Object mTag; 1497b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell 14981357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 14991357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * The default playback type, "local", indicating the presentation of the media is happening 15001357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * on the same device (e.g. a phone, a tablet) as where it is controlled from. 150169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * @see #getPlaybackType() 15021357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 15031357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public final static int PLAYBACK_TYPE_LOCAL = 0; 15041357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 15051357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * A playback type indicating the presentation of the media is happening on 15061357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * a different device (i.e. the remote device) than where it is controlled from. 150769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * @see #getPlaybackType() 15081357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 15091357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public final static int PLAYBACK_TYPE_REMOTE = 1; 15101357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 15111357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * Playback information indicating the playback volume is fixed, i.e. it cannot be 15121357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * controlled from this object. An example of fixed playback volume is a remote player, 15131357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * playing over HDMI where the user prefers to control the volume on the HDMI sink, rather 15141357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * than attenuate at the source. 151569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * @see #getVolumeHandling() 15161357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 15171357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public final static int PLAYBACK_VOLUME_FIXED = 0; 15181357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 15191357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * Playback information indicating the playback volume is variable and can be controlled 15201357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * from this object. 152169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * @see #getVolumeHandling() 15221357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 15231357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public final static int PLAYBACK_VOLUME_VARIABLE = 1; 15241357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 15259a1de308cea2d160778fd977825f10a07b49d738Adam Powell RouteInfo(RouteCategory category) { 15269a1de308cea2d160778fd977825f10a07b49d738Adam Powell mCategory = category; 15279a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 15289a1de308cea2d160778fd977825f10a07b49d738Adam Powell 15299a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 153056d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * Gets the user-visible name of the route. 153156d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * <p> 153256d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * The route name identifies the destination represented by the route. 153356d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * It may be a user-supplied name, an alias, or device serial number. 153456d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * </p> 153556d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * 153656d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * @return The user-visible name of a media route. This is the string presented 15379a1de308cea2d160778fd977825f10a07b49d738Adam Powell * to users who may select this as the active route. 15389a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 15399a1de308cea2d160778fd977825f10a07b49d738Adam Powell public CharSequence getName() { 15400d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell return getName(sStatic.mResources); 15410d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell } 154256d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown 15430d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell /** 154456d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * Return the properly localized/resource user-visible name of this route. 154556d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * <p> 154656d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * The route name identifies the destination represented by the route. 154756d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * It may be a user-supplied name, an alias, or device serial number. 154856d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * </p> 154956d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * 15500d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * @param context Context used to resolve the correct configuration to load 155156d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * @return The user-visible name of a media route. This is the string presented 15520d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * to users who may select this as the active route. 15530d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell */ 15540d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public CharSequence getName(Context context) { 15550d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell return getName(context.getResources()); 15560d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell } 155756d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown 15580d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell CharSequence getName(Resources res) { 15590d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell if (mNameResId != 0) { 15600d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell return mName = res.getText(mNameResId); 15610d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell } 15629a1de308cea2d160778fd977825f10a07b49d738Adam Powell return mName; 15639a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 15649a1de308cea2d160778fd977825f10a07b49d738Adam Powell 15659a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 156656d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * Gets the user-visible description of the route. 156756d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * <p> 156856d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * The route description describes the kind of destination represented by the route. 156956d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * It may be a user-supplied string, a model number or brand of device. 157056d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * </p> 157156d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * 157256d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * @return The description of the route, or null if none. 157356d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown */ 157456d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown public CharSequence getDescription() { 157556d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown return mDescription; 157656d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown } 157756d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown 157856d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown /** 157956d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * @return The user-visible status for a media route. This may include a description 15809a1de308cea2d160778fd977825f10a07b49d738Adam Powell * of the currently playing media, if available. 15819a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 15829a1de308cea2d160778fd977825f10a07b49d738Adam Powell public CharSequence getStatus() { 15839a1de308cea2d160778fd977825f10a07b49d738Adam Powell return mStatus; 15849a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 15859a1de308cea2d160778fd977825f10a07b49d738Adam Powell 15869a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 1587705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell * Set this route's status by predetermined status code. If the caller 1588705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell * should dispatch a route changed event this call will return true; 1589705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell */ 159039ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown boolean setRealStatusCode(int statusCode) { 159139ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown if (mRealStatusCode != statusCode) { 159239ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown mRealStatusCode = statusCode; 159339ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown return resolveStatusCode(); 159439ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown } 159539ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown return false; 159639ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown } 159739ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown 159839ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown /** 159939ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown * Resolves the status code whenever the real status code or selection state 160039ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown * changes. 160139ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown */ 160239ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown boolean resolveStatusCode() { 160339ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown int statusCode = mRealStatusCode; 160439ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown if (isSelected()) { 1605705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell switch (statusCode) { 160639ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown // If the route is selected and its status appears to be between states 160739ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown // then report it as connecting even though it has not yet had a chance 160839ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown // to officially move into the CONNECTING state. Note that routes in 160939ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown // the NONE state are assumed to not require an explicit connection 161039ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown // lifecycle whereas those that are AVAILABLE are assumed to have 161139ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown // to eventually proceed to CONNECTED. 1612705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell case STATUS_AVAILABLE: 161339ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown case STATUS_SCANNING: 161439ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown statusCode = STATUS_CONNECTING; 161569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown break; 1616705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1617705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 161839ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown if (mResolvedStatusCode == statusCode) { 161939ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown return false; 162039ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown } 162139ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown 162239ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown mResolvedStatusCode = statusCode; 162339ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown int resId; 162439ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown switch (statusCode) { 162539ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown case STATUS_SCANNING: 162639ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown resId = com.android.internal.R.string.media_route_status_scanning; 162739ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown break; 162839ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown case STATUS_CONNECTING: 162939ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown resId = com.android.internal.R.string.media_route_status_connecting; 163039ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown break; 163139ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown case STATUS_AVAILABLE: 163239ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown resId = com.android.internal.R.string.media_route_status_available; 163339ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown break; 163439ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown case STATUS_NOT_AVAILABLE: 163539ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown resId = com.android.internal.R.string.media_route_status_not_available; 163639ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown break; 163739ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown case STATUS_IN_USE: 163839ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown resId = com.android.internal.R.string.media_route_status_in_use; 163939ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown break; 164039ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown case STATUS_CONNECTED: 164139ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown case STATUS_NONE: 164239ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown default: 164339ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown resId = 0; 164439ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown break; 164539ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown } 164639ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown mStatus = resId != 0 ? sStatic.mResources.getText(resId) : null; 164739ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown return true; 1648705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1649705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 1650705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell /** 16512ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell * @hide 16522ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell */ 16532ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell public int getStatusCode() { 165439ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown return mResolvedStatusCode; 16552ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell } 16562ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell 16572ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell /** 16589a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @return A media type flag set describing which types this route supports. 16599a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 16609a1de308cea2d160778fd977825f10a07b49d738Adam Powell public int getSupportedTypes() { 16619a1de308cea2d160778fd977825f10a07b49d738Adam Powell return mSupportedTypes; 16629a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 16639a1de308cea2d160778fd977825f10a07b49d738Adam Powell 16640abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown /** @hide */ 16650abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown public boolean matchesTypes(int types) { 16660abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown return (mSupportedTypes & types) != 0; 16670abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown } 16680abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown 16699a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 16709a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @return The group that this route belongs to. 16719a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 16729a1de308cea2d160778fd977825f10a07b49d738Adam Powell public RouteGroup getGroup() { 16739a1de308cea2d160778fd977825f10a07b49d738Adam Powell return mGroup; 16749a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 16759a1de308cea2d160778fd977825f10a07b49d738Adam Powell 16769a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 16779a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @return the category this route belongs to. 16789a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 16799a1de308cea2d160778fd977825f10a07b49d738Adam Powell public RouteCategory getCategory() { 16809a1de308cea2d160778fd977825f10a07b49d738Adam Powell return mCategory; 16819a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 16829a1de308cea2d160778fd977825f10a07b49d738Adam Powell 1683ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell /** 1684ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * Get the icon representing this route. 1685ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * This icon will be used in picker UIs if available. 1686ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * 1687ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * @return the icon representing this route or null if no icon is available 1688ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell */ 1689ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell public Drawable getIconDrawable() { 1690ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell return mIcon; 1691ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell } 1692ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell 1693b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell /** 1694b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell * Set an application-specific tag object for this route. 1695b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell * The application may use this to store arbitrary data associated with the 1696b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell * route for internal tracking. 1697b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell * 1698b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell * <p>Note that the lifespan of a route may be well past the lifespan of 1699b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell * an Activity or other Context; take care that objects you store here 1700b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell * will not keep more data in memory alive than you intend.</p> 1701b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell * 1702b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell * @param tag Arbitrary, app-specific data for this route to hold for later use 1703b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell */ 1704b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell public void setTag(Object tag) { 1705b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell mTag = tag; 1706130b4572d1f3df702e5b296a655d15a41f6d4c66Adam Powell routeUpdated(); 1707b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell } 1708b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell 1709b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell /** 1710b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell * @return The tag object previously set by the application 1711b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell * @see #setTag(Object) 1712b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell */ 1713b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell public Object getTag() { 1714b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell return mTag; 1715b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell } 1716b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell 17171357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 17181357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @return the type of playback associated with this route 17191357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @see UserRouteInfo#setPlaybackType(int) 17201357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 17211357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public int getPlaybackType() { 17221357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi return mPlaybackType; 17231357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 17241357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 17251357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 17261357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @return the stream over which the playback associated with this route is performed 17271357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @see UserRouteInfo#setPlaybackStream(int) 17281357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 17291357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public int getPlaybackStream() { 17301357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi return mPlaybackStream; 17311357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 17321357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 17331357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 17348e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * Return the current volume for this route. Depending on the route, this may only 17358e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * be valid if the route is currently selected. 17368e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * 17371357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @return the volume at which the playback associated with this route is performed 17381357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @see UserRouteInfo#setVolume(int) 17391357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 17401357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public int getVolume() { 17411357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi if (mPlaybackType == PLAYBACK_TYPE_LOCAL) { 17421357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi int vol = 0; 17431357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi try { 17441357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi vol = sStatic.mAudioService.getStreamVolume(mPlaybackStream); 17451357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } catch (RemoteException e) { 17461357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi Log.e(TAG, "Error getting local stream volume", e); 17471357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 17481357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi return vol; 17491357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } else { 17501357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi return mVolume; 17511357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 17521357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 17531357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 17541357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 17558e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * Request a volume change for this route. 17568e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * @param volume value between 0 and getVolumeMax 17578e37a85bf3dc39519942698dc90a3951306b934bAdam Powell */ 17588e37a85bf3dc39519942698dc90a3951306b934bAdam Powell public void requestSetVolume(int volume) { 17598e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (mPlaybackType == PLAYBACK_TYPE_LOCAL) { 17608e37a85bf3dc39519942698dc90a3951306b934bAdam Powell try { 1761ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn sStatic.mAudioService.setStreamVolume(mPlaybackStream, volume, 0, 1762ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn ActivityThread.currentPackageName()); 17638e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } catch (RemoteException e) { 17648e37a85bf3dc39519942698dc90a3951306b934bAdam Powell Log.e(TAG, "Error setting local stream volume", e); 17658e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 17668e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } else { 176769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown sStatic.requestSetVolume(this, volume); 17688e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 17698e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 17708e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 17718e37a85bf3dc39519942698dc90a3951306b934bAdam Powell /** 17728e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * Request an incremental volume update for this route. 17738e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * @param direction Delta to apply to the current volume 17748e37a85bf3dc39519942698dc90a3951306b934bAdam Powell */ 17758e37a85bf3dc39519942698dc90a3951306b934bAdam Powell public void requestUpdateVolume(int direction) { 17768e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (mPlaybackType == PLAYBACK_TYPE_LOCAL) { 17778e37a85bf3dc39519942698dc90a3951306b934bAdam Powell try { 17788e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final int volume = 17798e37a85bf3dc39519942698dc90a3951306b934bAdam Powell Math.max(0, Math.min(getVolume() + direction, getVolumeMax())); 1780ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn sStatic.mAudioService.setStreamVolume(mPlaybackStream, volume, 0, 1781ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn ActivityThread.currentPackageName()); 17828e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } catch (RemoteException e) { 17838e37a85bf3dc39519942698dc90a3951306b934bAdam Powell Log.e(TAG, "Error setting local stream volume", e); 17848e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 17858e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } else { 178669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown sStatic.requestUpdateVolume(this, direction); 17878e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 17888e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 17898e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 17908e37a85bf3dc39519942698dc90a3951306b934bAdam Powell /** 17911357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @return the maximum volume at which the playback associated with this route is performed 17921357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @see UserRouteInfo#setVolumeMax(int) 17931357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 17941357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public int getVolumeMax() { 17951357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi if (mPlaybackType == PLAYBACK_TYPE_LOCAL) { 17961357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi int volMax = 0; 17971357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi try { 17981357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi volMax = sStatic.mAudioService.getStreamMaxVolume(mPlaybackStream); 17991357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } catch (RemoteException e) { 18001357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi Log.e(TAG, "Error getting local stream volume", e); 18011357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 18021357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi return volMax; 18031357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } else { 18041357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi return mVolumeMax; 18051357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 18061357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 18071357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 18081357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 18091357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @return how volume is handling on the route 18101357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @see UserRouteInfo#setVolumeHandling(int) 18111357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 18121357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public int getVolumeHandling() { 18131357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi return mVolumeHandling; 18141357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 18151357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 1816705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell /** 181792130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * Gets the {@link Display} that should be used by the application to show 181892130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * a {@link android.app.Presentation} on an external display when this route is selected. 181992130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * Depending on the route, this may only be valid if the route is currently 182092130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * selected. 182192130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * <p> 182292130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * The preferred presentation display may change independently of the route 182392130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * being selected or unselected. For example, the presentation display 182492130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * of the default system route may change when an external HDMI display is connected 182592130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * or disconnected even though the route itself has not changed. 182692130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * </p><p> 182792130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * This method may return null if there is no external display associated with 182892130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * the route or if the display is not ready to show UI yet. 182992130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * </p><p> 183092130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * The application should listen for changes to the presentation display 183192130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * using the {@link Callback#onRoutePresentationDisplayChanged} callback and 183292130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * show or dismiss its {@link android.app.Presentation} accordingly when the display 183392130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * becomes available or is removed. 183492130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * </p><p> 183592130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * This method only makes sense for {@link #ROUTE_TYPE_LIVE_VIDEO live video} routes. 183692130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * </p> 183792130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * 183892130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * @return The preferred presentation display to use when this route is 183992130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * selected or null if none. 184092130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * 184192130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * @see #ROUTE_TYPE_LIVE_VIDEO 184292130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * @see android.app.Presentation 184392130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown */ 184492130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown public Display getPresentationDisplay() { 184592130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown return mPresentationDisplay; 184692130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown } 184792130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown 18485830b0b33618940d65197cec99d697b21908fec8Chong Zhang boolean updatePresentationDisplay() { 18495830b0b33618940d65197cec99d697b21908fec8Chong Zhang Display display = choosePresentationDisplay(); 18505830b0b33618940d65197cec99d697b21908fec8Chong Zhang if (mPresentationDisplay != display) { 18515830b0b33618940d65197cec99d697b21908fec8Chong Zhang mPresentationDisplay = display; 18525830b0b33618940d65197cec99d697b21908fec8Chong Zhang return true; 18535830b0b33618940d65197cec99d697b21908fec8Chong Zhang } 18545830b0b33618940d65197cec99d697b21908fec8Chong Zhang return false; 18555830b0b33618940d65197cec99d697b21908fec8Chong Zhang } 18565830b0b33618940d65197cec99d697b21908fec8Chong Zhang 18575830b0b33618940d65197cec99d697b21908fec8Chong Zhang private Display choosePresentationDisplay() { 18585830b0b33618940d65197cec99d697b21908fec8Chong Zhang if ((mSupportedTypes & ROUTE_TYPE_LIVE_VIDEO) != 0) { 18595830b0b33618940d65197cec99d697b21908fec8Chong Zhang Display[] displays = sStatic.getAllPresentationDisplays(); 18605830b0b33618940d65197cec99d697b21908fec8Chong Zhang 18615830b0b33618940d65197cec99d697b21908fec8Chong Zhang // Ensure that the specified display is valid for presentations. 18625830b0b33618940d65197cec99d697b21908fec8Chong Zhang // This check will normally disallow the default display unless it was 18635830b0b33618940d65197cec99d697b21908fec8Chong Zhang // configured as a presentation display for some reason. 18645830b0b33618940d65197cec99d697b21908fec8Chong Zhang if (mPresentationDisplayId >= 0) { 18655830b0b33618940d65197cec99d697b21908fec8Chong Zhang for (Display display : displays) { 18665830b0b33618940d65197cec99d697b21908fec8Chong Zhang if (display.getDisplayId() == mPresentationDisplayId) { 18675830b0b33618940d65197cec99d697b21908fec8Chong Zhang return display; 18685830b0b33618940d65197cec99d697b21908fec8Chong Zhang } 18695830b0b33618940d65197cec99d697b21908fec8Chong Zhang } 18705830b0b33618940d65197cec99d697b21908fec8Chong Zhang return null; 18715830b0b33618940d65197cec99d697b21908fec8Chong Zhang } 18725830b0b33618940d65197cec99d697b21908fec8Chong Zhang 18735830b0b33618940d65197cec99d697b21908fec8Chong Zhang // Find the indicated Wifi display by its address. 18745830b0b33618940d65197cec99d697b21908fec8Chong Zhang if (mDeviceAddress != null) { 18755830b0b33618940d65197cec99d697b21908fec8Chong Zhang for (Display display : displays) { 18765830b0b33618940d65197cec99d697b21908fec8Chong Zhang if (display.getType() == Display.TYPE_WIFI 18775830b0b33618940d65197cec99d697b21908fec8Chong Zhang && mDeviceAddress.equals(display.getAddress())) { 18785830b0b33618940d65197cec99d697b21908fec8Chong Zhang return display; 18795830b0b33618940d65197cec99d697b21908fec8Chong Zhang } 18805830b0b33618940d65197cec99d697b21908fec8Chong Zhang } 18815830b0b33618940d65197cec99d697b21908fec8Chong Zhang return null; 18825830b0b33618940d65197cec99d697b21908fec8Chong Zhang } 18835830b0b33618940d65197cec99d697b21908fec8Chong Zhang 18845830b0b33618940d65197cec99d697b21908fec8Chong Zhang // For the default route, choose the first presentation display from the list. 18855830b0b33618940d65197cec99d697b21908fec8Chong Zhang if (this == sStatic.mDefaultAudioVideo && displays.length > 0) { 18865830b0b33618940d65197cec99d697b21908fec8Chong Zhang return displays[0]; 18875830b0b33618940d65197cec99d697b21908fec8Chong Zhang } 18885830b0b33618940d65197cec99d697b21908fec8Chong Zhang } 18895830b0b33618940d65197cec99d697b21908fec8Chong Zhang return null; 18905830b0b33618940d65197cec99d697b21908fec8Chong Zhang } 18915830b0b33618940d65197cec99d697b21908fec8Chong Zhang 189275af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown /** @hide */ 189375af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown public String getDeviceAddress() { 189475af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown return mDeviceAddress; 189575af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown } 189675af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown 189792130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown /** 1898a27b8fb4296c1271ddf5916843ddffda6764e65fJeff Brown * Returns true if this route is enabled and may be selected. 1899a27b8fb4296c1271ddf5916843ddffda6764e65fJeff Brown * 1900a27b8fb4296c1271ddf5916843ddffda6764e65fJeff Brown * @return True if this route is enabled. 1901705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell */ 1902705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell public boolean isEnabled() { 1903705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell return mEnabled; 1904705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1905705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 1906a27b8fb4296c1271ddf5916843ddffda6764e65fJeff Brown /** 1907a27b8fb4296c1271ddf5916843ddffda6764e65fJeff Brown * Returns true if the route is in the process of connecting and is not 1908a27b8fb4296c1271ddf5916843ddffda6764e65fJeff Brown * yet ready for use. 1909a27b8fb4296c1271ddf5916843ddffda6764e65fJeff Brown * 1910a27b8fb4296c1271ddf5916843ddffda6764e65fJeff Brown * @return True if this route is in the process of connecting. 1911a27b8fb4296c1271ddf5916843ddffda6764e65fJeff Brown */ 1912a27b8fb4296c1271ddf5916843ddffda6764e65fJeff Brown public boolean isConnecting() { 191339ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown return mResolvedStatusCode == STATUS_CONNECTING; 19140abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown } 19150abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown 19160abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown /** @hide */ 19170abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown public boolean isSelected() { 19180abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown return this == sStatic.mSelectedRoute; 19190abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown } 19200abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown 19210abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown /** @hide */ 19220abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown public boolean isDefault() { 19230abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown return this == sStatic.mDefaultAudioVideo; 19240abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown } 19250abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown 19260abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown /** @hide */ 19270abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown public void select() { 19280abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown selectRouteStatic(mSupportedTypes, this, true); 1929a27b8fb4296c1271ddf5916843ddffda6764e65fJeff Brown } 1930a27b8fb4296c1271ddf5916843ddffda6764e65fJeff Brown 19319a1de308cea2d160778fd977825f10a07b49d738Adam Powell void setStatusInt(CharSequence status) { 19329a1de308cea2d160778fd977825f10a07b49d738Adam Powell if (!status.equals(mStatus)) { 19339a1de308cea2d160778fd977825f10a07b49d738Adam Powell mStatus = status; 19349a1de308cea2d160778fd977825f10a07b49d738Adam Powell if (mGroup != null) { 19359a1de308cea2d160778fd977825f10a07b49d738Adam Powell mGroup.memberStatusChanged(this, status); 19369a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 19379a1de308cea2d160778fd977825f10a07b49d738Adam Powell routeUpdated(); 19389a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 19399a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 19409a1de308cea2d160778fd977825f10a07b49d738Adam Powell 19411357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi final IRemoteVolumeObserver.Stub mRemoteVolObserver = new IRemoteVolumeObserver.Stub() { 194269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown @Override 19431357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public void dispatchRemoteVolumeUpdate(final int direction, final int value) { 19441357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi sStatic.mHandler.post(new Runnable() { 19451357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi @Override 19461357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public void run() { 19471357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi if (mVcb != null) { 19481357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi if (direction != 0) { 19491357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi mVcb.vcb.onVolumeUpdateRequest(mVcb.route, direction); 19501357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } else { 19511357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi mVcb.vcb.onVolumeSetRequest(mVcb.route, value); 19521357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 19531357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 19541357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 19551357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi }); 19561357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 19571357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi }; 19581357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 19599a1de308cea2d160778fd977825f10a07b49d738Adam Powell void routeUpdated() { 19609a1de308cea2d160778fd977825f10a07b49d738Adam Powell updateRoute(this); 19619a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 19629a1de308cea2d160778fd977825f10a07b49d738Adam Powell 19639a1de308cea2d160778fd977825f10a07b49d738Adam Powell @Override 19649a1de308cea2d160778fd977825f10a07b49d738Adam Powell public String toString() { 1965d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell String supportedTypes = typesToString(getSupportedTypes()); 196692130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown return getClass().getSimpleName() + "{ name=" + getName() + 196756d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown ", description=" + getDescription() + 196892130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown ", status=" + getStatus() + 196992130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown ", category=" + getCategory() + 197092130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown ", supportedTypes=" + supportedTypes + 197169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown ", presentationDisplay=" + mPresentationDisplay + " }"; 19729a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 19739a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 19749a1de308cea2d160778fd977825f10a07b49d738Adam Powell 19759a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 19769a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Information about a route that the application may define and modify. 19778e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * A user route defaults to {@link RouteInfo#PLAYBACK_TYPE_REMOTE} and 19788e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * {@link RouteInfo#PLAYBACK_VOLUME_FIXED}. 19799a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 19809a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @see MediaRouter.RouteInfo 19819a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 1982b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn public static class UserRouteInfo extends RouteInfo { 1983ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell RemoteControlClient mRcc; 19845d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik SessionVolumeProvider mSvp; 19859a1de308cea2d160778fd977825f10a07b49d738Adam Powell 19869a1de308cea2d160778fd977825f10a07b49d738Adam Powell UserRouteInfo(RouteCategory category) { 19879a1de308cea2d160778fd977825f10a07b49d738Adam Powell super(category); 19889a1de308cea2d160778fd977825f10a07b49d738Adam Powell mSupportedTypes = ROUTE_TYPE_USER; 19898e37a85bf3dc39519942698dc90a3951306b934bAdam Powell mPlaybackType = PLAYBACK_TYPE_REMOTE; 19908e37a85bf3dc39519942698dc90a3951306b934bAdam Powell mVolumeHandling = PLAYBACK_VOLUME_FIXED; 19919a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 19929a1de308cea2d160778fd977825f10a07b49d738Adam Powell 19939a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 19949a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Set the user-visible name of this route. 19959a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param name Name to display to the user to describe this route 19969a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 19979a1de308cea2d160778fd977825f10a07b49d738Adam Powell public void setName(CharSequence name) { 19989a1de308cea2d160778fd977825f10a07b49d738Adam Powell mName = name; 19999a1de308cea2d160778fd977825f10a07b49d738Adam Powell routeUpdated(); 20009a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 20015d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik 20020d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell /** 20030d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * Set the user-visible name of this route. 200456d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * <p> 200556d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * The route name identifies the destination represented by the route. 200656d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * It may be a user-supplied name, an alias, or device serial number. 200756d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * </p> 200856d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * 20090d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * @param resId Resource ID of the name to display to the user to describe this route 20100d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell */ 20110d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public void setName(int resId) { 20120d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell mNameResId = resId; 20130d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell mName = null; 20140d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell routeUpdated(); 20150d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell } 20169a1de308cea2d160778fd977825f10a07b49d738Adam Powell 20179a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 201856d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * Set the user-visible description of this route. 201956d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * <p> 202056d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * The route description describes the kind of destination represented by the route. 202156d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * It may be a user-supplied string, a model number or brand of device. 202256d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * </p> 202356d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * 202456d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * @param description The description of the route, or null if none. 202556d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown */ 202656d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown public void setDescription(CharSequence description) { 202756d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown mDescription = description; 202856d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown routeUpdated(); 202956d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown } 203056d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown 203156d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown /** 20329a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Set the current user-visible status for this route. 20339a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param status Status to display to the user to describe what the endpoint 20349a1de308cea2d160778fd977825f10a07b49d738Adam Powell * of this route is currently doing 20359a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 20369a1de308cea2d160778fd977825f10a07b49d738Adam Powell public void setStatus(CharSequence status) { 20379a1de308cea2d160778fd977825f10a07b49d738Adam Powell setStatusInt(status); 20389a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 2039ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell 2040ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell /** 2041ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * Set the RemoteControlClient responsible for reporting playback info for this 2042ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * user route. 2043ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * 2044ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * <p>If this route manages remote playback, the data exposed by this 2045ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * RemoteControlClient will be used to reflect and update information 2046ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * such as route volume info in related UIs.</p> 2047ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * 20481357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * <p>The RemoteControlClient must have been previously registered with 20491357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * {@link AudioManager#registerRemoteControlClient(RemoteControlClient)}.</p> 20501357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * 2051ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * @param rcc RemoteControlClient associated with this route 2052ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell */ 2053ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell public void setRemoteControlClient(RemoteControlClient rcc) { 2054ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell mRcc = rcc; 20551357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi updatePlaybackInfoOnRcc(); 2056ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell } 2057ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell 2058ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell /** 20594599696591f745b3a546197d2ba7e5cfc5562484Adam Powell * Retrieve the RemoteControlClient associated with this route, if one has been set. 20604599696591f745b3a546197d2ba7e5cfc5562484Adam Powell * 20614599696591f745b3a546197d2ba7e5cfc5562484Adam Powell * @return the RemoteControlClient associated with this route 20624599696591f745b3a546197d2ba7e5cfc5562484Adam Powell * @see #setRemoteControlClient(RemoteControlClient) 20634599696591f745b3a546197d2ba7e5cfc5562484Adam Powell */ 20644599696591f745b3a546197d2ba7e5cfc5562484Adam Powell public RemoteControlClient getRemoteControlClient() { 20654599696591f745b3a546197d2ba7e5cfc5562484Adam Powell return mRcc; 20664599696591f745b3a546197d2ba7e5cfc5562484Adam Powell } 20674599696591f745b3a546197d2ba7e5cfc5562484Adam Powell 20684599696591f745b3a546197d2ba7e5cfc5562484Adam Powell /** 2069ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * Set an icon that will be used to represent this route. 2070ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * The system may use this icon in picker UIs or similar. 2071ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * 2072ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * @param icon icon drawable to use to represent this route 2073ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell */ 2074ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell public void setIconDrawable(Drawable icon) { 2075ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell mIcon = icon; 2076ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell } 2077ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell 2078ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell /** 2079ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * Set an icon that will be used to represent this route. 2080ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * The system may use this icon in picker UIs or similar. 2081ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * 208271c69897ad0a55d590698bfa399bfe99c763b9dbAdam Powell * @param resId Resource ID of an icon drawable to use to represent this route 2083ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell */ 2084ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell public void setIconResource(int resId) { 2085ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell setIconDrawable(sStatic.mResources.getDrawable(resId)); 2086ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell } 20871357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 20881357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 20891357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * Set a callback to be notified of volume update requests 20901357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @param vcb 20911357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 20921357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public void setVolumeCallback(VolumeCallback vcb) { 20931357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi mVcb = new VolumeCallbackInfo(vcb, this); 20941357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 20951357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 20961357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 20971357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * Defines whether playback associated with this route is "local" 20981357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * ({@link RouteInfo#PLAYBACK_TYPE_LOCAL}) or "remote" 20991357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * ({@link RouteInfo#PLAYBACK_TYPE_REMOTE}). 21001357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @param type 21011357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 21021357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public void setPlaybackType(int type) { 21031357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi if (mPlaybackType != type) { 21041357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi mPlaybackType = type; 2105430fc48865e5a371b08f180390946b96d73848feRoboErik configureSessionVolume(); 21061357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 21071357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 21081357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 21091357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 21101357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * Defines whether volume for the playback associated with this route is fixed 21111357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * ({@link RouteInfo#PLAYBACK_VOLUME_FIXED}) or can modified 21121357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * ({@link RouteInfo#PLAYBACK_VOLUME_VARIABLE}). 21131357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @param volumeHandling 21141357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 21151357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public void setVolumeHandling(int volumeHandling) { 21161357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi if (mVolumeHandling != volumeHandling) { 21171357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi mVolumeHandling = volumeHandling; 2118430fc48865e5a371b08f180390946b96d73848feRoboErik configureSessionVolume(); 21191357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 21201357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 21211357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 21221357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 21231357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * Defines at what volume the playback associated with this route is performed (for user 21241357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * feedback purposes). This information is only used when the playback is not local. 21251357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @param volume 21261357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 21271357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public void setVolume(int volume) { 21288e37a85bf3dc39519942698dc90a3951306b934bAdam Powell volume = Math.max(0, Math.min(volume, getVolumeMax())); 21291357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi if (mVolume != volume) { 21301357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi mVolume = volume; 2131430fc48865e5a371b08f180390946b96d73848feRoboErik if (mSvp != null) { 2132430fc48865e5a371b08f180390946b96d73848feRoboErik mSvp.notifyVolumeChanged(); 21335d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik } 21348e37a85bf3dc39519942698dc90a3951306b934bAdam Powell dispatchRouteVolumeChanged(this); 2135f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell if (mGroup != null) { 2136f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell mGroup.memberVolumeChanged(this); 2137f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell } 21388e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 21398e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 21408e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 21418e37a85bf3dc39519942698dc90a3951306b934bAdam Powell @Override 21428e37a85bf3dc39519942698dc90a3951306b934bAdam Powell public void requestSetVolume(int volume) { 21438e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (mVolumeHandling == PLAYBACK_VOLUME_VARIABLE) { 21448e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (mVcb == null) { 21458e37a85bf3dc39519942698dc90a3951306b934bAdam Powell Log.e(TAG, "Cannot requestSetVolume on user route - no volume callback set"); 21468e37a85bf3dc39519942698dc90a3951306b934bAdam Powell return; 21478e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 21488e37a85bf3dc39519942698dc90a3951306b934bAdam Powell mVcb.vcb.onVolumeSetRequest(this, volume); 21498e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 21508e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 21518e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 21528e37a85bf3dc39519942698dc90a3951306b934bAdam Powell @Override 21538e37a85bf3dc39519942698dc90a3951306b934bAdam Powell public void requestUpdateVolume(int direction) { 21548e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (mVolumeHandling == PLAYBACK_VOLUME_VARIABLE) { 21558e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (mVcb == null) { 21568e37a85bf3dc39519942698dc90a3951306b934bAdam Powell Log.e(TAG, "Cannot requestChangeVolume on user route - no volumec callback set"); 21578e37a85bf3dc39519942698dc90a3951306b934bAdam Powell return; 21588e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 21598e37a85bf3dc39519942698dc90a3951306b934bAdam Powell mVcb.vcb.onVolumeUpdateRequest(this, direction); 21601357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 21611357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 21621357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 21631357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 21641357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * Defines the maximum volume at which the playback associated with this route is performed 21651357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * (for user feedback purposes). This information is only used when the playback is not 21661357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * local. 21671357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @param volumeMax 21681357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 21691357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public void setVolumeMax(int volumeMax) { 21701357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi if (mVolumeMax != volumeMax) { 21711357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi mVolumeMax = volumeMax; 2172430fc48865e5a371b08f180390946b96d73848feRoboErik configureSessionVolume(); 21731357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 21741357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 21751357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 21761357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 21771357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * Defines over what stream type the media is presented. 21781357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @param stream 21791357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 21801357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public void setPlaybackStream(int stream) { 21811357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi if (mPlaybackStream != stream) { 21821357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi mPlaybackStream = stream; 2183430fc48865e5a371b08f180390946b96d73848feRoboErik configureSessionVolume(); 21841357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 21851357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 21861357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 21871357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi private void updatePlaybackInfoOnRcc() { 2188430fc48865e5a371b08f180390946b96d73848feRoboErik configureSessionVolume(); 21895d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik } 21905d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik 21915d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik private void configureSessionVolume() { 21925d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik if (mRcc == null) { 21935d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik if (DEBUG) { 21945d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik Log.d(TAG, "No Rcc to configure volume for route " + mName); 21955d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik } 21965d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik return; 21975d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik } 21985d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik MediaSession session = mRcc.getMediaSession(); 21995d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik if (session == null) { 22005d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik if (DEBUG) { 22015d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik Log.d(TAG, "Rcc has no session to configure volume"); 22025d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik } 22035d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik return; 22045d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik } 22055d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik if (mPlaybackType == RemoteControlClient.PLAYBACK_TYPE_REMOTE) { 2206ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik int volumeControl = VolumeProvider.VOLUME_CONTROL_FIXED; 22075d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik switch (mVolumeHandling) { 22085d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik case RemoteControlClient.PLAYBACK_VOLUME_VARIABLE: 2209ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik volumeControl = VolumeProvider.VOLUME_CONTROL_ABSOLUTE; 22105d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik break; 22115d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik case RemoteControlClient.PLAYBACK_VOLUME_FIXED: 22125d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik default: 22135d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik break; 22141357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 22155d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik // Only register a new listener if necessary 22165d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik if (mSvp == null || mSvp.getVolumeControl() != volumeControl 22175d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik || mSvp.getMaxVolume() != mVolumeMax) { 22185d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik mSvp = new SessionVolumeProvider(volumeControl, mVolumeMax); 22195d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik session.setPlaybackToRemote(mSvp); 22205d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik } 22215d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik } else { 22225d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik // We only know how to handle local and remote, fall back to local if not remote. 22235d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik session.setPlaybackToLocal(mPlaybackStream); 22245d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik mSvp = null; 22251357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 22261357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 22271357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 2228ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik class SessionVolumeProvider extends VolumeProvider { 22295d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik 22305d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik public SessionVolumeProvider(int volumeControl, int maxVolume) { 22315d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik super(volumeControl, maxVolume); 22325d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik } 22335d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik 22345d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik @Override 22355d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik public int onGetCurrentVolume() { 22365d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik return mVcb == null ? 0 : mVcb.route.mVolume; 22375d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik } 22385d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik 22395d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik @Override 22405d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik public void onSetVolumeTo(final int volume) { 22415d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik sStatic.mHandler.post(new Runnable() { 22425d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik @Override 22435d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik public void run() { 22445d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik if (mVcb != null) { 22455d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik mVcb.vcb.onVolumeSetRequest(mVcb.route, volume); 22465d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik } 22475d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik } 22485d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik }); 22495d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik } 22505d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik 22515d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik @Override 22525d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik public void onAdjustVolumeBy(final int delta) { 22535d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik sStatic.mHandler.post(new Runnable() { 22545d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik @Override 22555d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik public void run() { 22565d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik if (mVcb != null) { 22575d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik mVcb.vcb.onVolumeUpdateRequest(mVcb.route, delta); 22585d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik } 22595d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik } 22605d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik }); 22615d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik } 22625d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik } 22639a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 22649a1de308cea2d160778fd977825f10a07b49d738Adam Powell 22659a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 22669a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Information about a route that consists of multiple other routes in a group. 22679a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 2268b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn public static class RouteGroup extends RouteInfo { 22699a1de308cea2d160778fd977825f10a07b49d738Adam Powell final ArrayList<RouteInfo> mRoutes = new ArrayList<RouteInfo>(); 22709a1de308cea2d160778fd977825f10a07b49d738Adam Powell private boolean mUpdateName; 22719a1de308cea2d160778fd977825f10a07b49d738Adam Powell 22729a1de308cea2d160778fd977825f10a07b49d738Adam Powell RouteGroup(RouteCategory category) { 22739a1de308cea2d160778fd977825f10a07b49d738Adam Powell super(category); 22749a1de308cea2d160778fd977825f10a07b49d738Adam Powell mGroup = this; 22758e37a85bf3dc39519942698dc90a3951306b934bAdam Powell mVolumeHandling = PLAYBACK_VOLUME_FIXED; 22769a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 22779a1de308cea2d160778fd977825f10a07b49d738Adam Powell 227869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown @Override 22790d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell CharSequence getName(Resources res) { 22809a1de308cea2d160778fd977825f10a07b49d738Adam Powell if (mUpdateName) updateName(); 22810d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell return super.getName(res); 22829a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 22839a1de308cea2d160778fd977825f10a07b49d738Adam Powell 22849a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 22859a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Add a route to this group. The route must not currently belong to another group. 22869a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 22879a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param route route to add to this group 22889a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 22899a1de308cea2d160778fd977825f10a07b49d738Adam Powell public void addRoute(RouteInfo route) { 22909a1de308cea2d160778fd977825f10a07b49d738Adam Powell if (route.getGroup() != null) { 22919a1de308cea2d160778fd977825f10a07b49d738Adam Powell throw new IllegalStateException("Route " + route + " is already part of a group."); 22929a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 22939a1de308cea2d160778fd977825f10a07b49d738Adam Powell if (route.getCategory() != mCategory) { 22949a1de308cea2d160778fd977825f10a07b49d738Adam Powell throw new IllegalArgumentException( 22959a1de308cea2d160778fd977825f10a07b49d738Adam Powell "Route cannot be added to a group with a different category. " + 22969a1de308cea2d160778fd977825f10a07b49d738Adam Powell "(Route category=" + route.getCategory() + 22979a1de308cea2d160778fd977825f10a07b49d738Adam Powell " group category=" + mCategory + ")"); 22989a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 2299d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell final int at = mRoutes.size(); 23009a1de308cea2d160778fd977825f10a07b49d738Adam Powell mRoutes.add(route); 2301d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell route.mGroup = this; 23029a1de308cea2d160778fd977825f10a07b49d738Adam Powell mUpdateName = true; 2303f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell updateVolume(); 23049a1de308cea2d160778fd977825f10a07b49d738Adam Powell routeUpdated(); 2305f3b653a21cdffe04c94c275e69ecb56e00766e82Adam Powell dispatchRouteGrouped(route, this, at); 23069a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 23079a1de308cea2d160778fd977825f10a07b49d738Adam Powell 23089a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 23099a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Add a route to this group before the specified index. 23109a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 23119a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param route route to add 23129a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param insertAt insert the new route before this index 23139a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 23149a1de308cea2d160778fd977825f10a07b49d738Adam Powell public void addRoute(RouteInfo route, int insertAt) { 23159a1de308cea2d160778fd977825f10a07b49d738Adam Powell if (route.getGroup() != null) { 23169a1de308cea2d160778fd977825f10a07b49d738Adam Powell throw new IllegalStateException("Route " + route + " is already part of a group."); 23179a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 23189a1de308cea2d160778fd977825f10a07b49d738Adam Powell if (route.getCategory() != mCategory) { 23199a1de308cea2d160778fd977825f10a07b49d738Adam Powell throw new IllegalArgumentException( 23209a1de308cea2d160778fd977825f10a07b49d738Adam Powell "Route cannot be added to a group with a different category. " + 23219a1de308cea2d160778fd977825f10a07b49d738Adam Powell "(Route category=" + route.getCategory() + 23229a1de308cea2d160778fd977825f10a07b49d738Adam Powell " group category=" + mCategory + ")"); 23239a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 23249a1de308cea2d160778fd977825f10a07b49d738Adam Powell mRoutes.add(insertAt, route); 2325d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell route.mGroup = this; 23269a1de308cea2d160778fd977825f10a07b49d738Adam Powell mUpdateName = true; 2327f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell updateVolume(); 23289a1de308cea2d160778fd977825f10a07b49d738Adam Powell routeUpdated(); 2329f3b653a21cdffe04c94c275e69ecb56e00766e82Adam Powell dispatchRouteGrouped(route, this, insertAt); 23309a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 23319a1de308cea2d160778fd977825f10a07b49d738Adam Powell 23329a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 23339a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Remove a route from this group. 23349a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 23359a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param route route to remove 23369a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 23379a1de308cea2d160778fd977825f10a07b49d738Adam Powell public void removeRoute(RouteInfo route) { 23389a1de308cea2d160778fd977825f10a07b49d738Adam Powell if (route.getGroup() != this) { 23399a1de308cea2d160778fd977825f10a07b49d738Adam Powell throw new IllegalArgumentException("Route " + route + 23409a1de308cea2d160778fd977825f10a07b49d738Adam Powell " is not a member of this group."); 23419a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 23429a1de308cea2d160778fd977825f10a07b49d738Adam Powell mRoutes.remove(route); 2343d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell route.mGroup = null; 23449a1de308cea2d160778fd977825f10a07b49d738Adam Powell mUpdateName = true; 2345f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell updateVolume(); 2346d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell dispatchRouteUngrouped(route, this); 23479a1de308cea2d160778fd977825f10a07b49d738Adam Powell routeUpdated(); 23489a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 23499a1de308cea2d160778fd977825f10a07b49d738Adam Powell 23509a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 23519a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Remove the route at the specified index from this group. 23529a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 23539a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param index index of the route to remove 23549a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 23559a1de308cea2d160778fd977825f10a07b49d738Adam Powell public void removeRoute(int index) { 2356d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell RouteInfo route = mRoutes.remove(index); 2357d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell route.mGroup = null; 23589a1de308cea2d160778fd977825f10a07b49d738Adam Powell mUpdateName = true; 2359f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell updateVolume(); 2360d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell dispatchRouteUngrouped(route, this); 23619a1de308cea2d160778fd977825f10a07b49d738Adam Powell routeUpdated(); 23629a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 23639a1de308cea2d160778fd977825f10a07b49d738Adam Powell 2364d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell /** 2365d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @return The number of routes in this group 2366d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell */ 2367d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell public int getRouteCount() { 2368d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell return mRoutes.size(); 2369d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell } 2370d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell 2371d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell /** 2372d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * Return the route in this group at the specified index 2373d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * 2374d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param index Index to fetch 2375d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @return The route at index 2376d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell */ 2377d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell public RouteInfo getRouteAt(int index) { 2378d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell return mRoutes.get(index); 2379d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell } 2380d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell 2381ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell /** 2382ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * Set an icon that will be used to represent this group. 2383ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * The system may use this icon in picker UIs or similar. 2384ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * 2385ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * @param icon icon drawable to use to represent this group 2386ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell */ 2387ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell public void setIconDrawable(Drawable icon) { 2388ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell mIcon = icon; 2389ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell } 2390ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell 2391ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell /** 2392ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * Set an icon that will be used to represent this group. 2393ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * The system may use this icon in picker UIs or similar. 2394ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * 239571c69897ad0a55d590698bfa399bfe99c763b9dbAdam Powell * @param resId Resource ID of an icon drawable to use to represent this group 2396ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell */ 2397ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell public void setIconResource(int resId) { 2398ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell setIconDrawable(sStatic.mResources.getDrawable(resId)); 2399ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell } 2400ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell 24018e37a85bf3dc39519942698dc90a3951306b934bAdam Powell @Override 24028e37a85bf3dc39519942698dc90a3951306b934bAdam Powell public void requestSetVolume(int volume) { 24038e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final int maxVol = getVolumeMax(); 24048e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (maxVol == 0) { 24058e37a85bf3dc39519942698dc90a3951306b934bAdam Powell return; 24068e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 24078e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 24088e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final float scaledVolume = (float) volume / maxVol; 24098e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final int routeCount = getRouteCount(); 24108e37a85bf3dc39519942698dc90a3951306b934bAdam Powell for (int i = 0; i < routeCount; i++) { 24118e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final RouteInfo route = getRouteAt(i); 24128e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final int routeVol = (int) (scaledVolume * route.getVolumeMax()); 24138e37a85bf3dc39519942698dc90a3951306b934bAdam Powell route.requestSetVolume(routeVol); 24148e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 24158e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (volume != mVolume) { 24168e37a85bf3dc39519942698dc90a3951306b934bAdam Powell mVolume = volume; 24178e37a85bf3dc39519942698dc90a3951306b934bAdam Powell dispatchRouteVolumeChanged(this); 24188e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 24198e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 24208e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 24218e37a85bf3dc39519942698dc90a3951306b934bAdam Powell @Override 24228e37a85bf3dc39519942698dc90a3951306b934bAdam Powell public void requestUpdateVolume(int direction) { 24238e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final int maxVol = getVolumeMax(); 24248e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (maxVol == 0) { 24258e37a85bf3dc39519942698dc90a3951306b934bAdam Powell return; 24268e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 24278e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 24288e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final int routeCount = getRouteCount(); 2429f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell int volume = 0; 24308e37a85bf3dc39519942698dc90a3951306b934bAdam Powell for (int i = 0; i < routeCount; i++) { 24318e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final RouteInfo route = getRouteAt(i); 24328e37a85bf3dc39519942698dc90a3951306b934bAdam Powell route.requestUpdateVolume(direction); 2433f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell final int routeVol = route.getVolume(); 2434f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell if (routeVol > volume) { 2435f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell volume = routeVol; 2436f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell } 24378e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 24388e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (volume != mVolume) { 24398e37a85bf3dc39519942698dc90a3951306b934bAdam Powell mVolume = volume; 24408e37a85bf3dc39519942698dc90a3951306b934bAdam Powell dispatchRouteVolumeChanged(this); 24418e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 24428e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 24438e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 24449a1de308cea2d160778fd977825f10a07b49d738Adam Powell void memberNameChanged(RouteInfo info, CharSequence name) { 24459a1de308cea2d160778fd977825f10a07b49d738Adam Powell mUpdateName = true; 24469a1de308cea2d160778fd977825f10a07b49d738Adam Powell routeUpdated(); 24479a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 24489a1de308cea2d160778fd977825f10a07b49d738Adam Powell 24499a1de308cea2d160778fd977825f10a07b49d738Adam Powell void memberStatusChanged(RouteInfo info, CharSequence status) { 24509a1de308cea2d160778fd977825f10a07b49d738Adam Powell setStatusInt(status); 24519a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 24529a1de308cea2d160778fd977825f10a07b49d738Adam Powell 2453f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell void memberVolumeChanged(RouteInfo info) { 2454f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell updateVolume(); 2455f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell } 2456f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell 2457f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell void updateVolume() { 2458f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell // A group always represents the highest component volume value. 2459f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell final int routeCount = getRouteCount(); 2460f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell int volume = 0; 2461f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell for (int i = 0; i < routeCount; i++) { 2462f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell final int routeVol = getRouteAt(i).getVolume(); 2463f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell if (routeVol > volume) { 2464f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell volume = routeVol; 2465f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell } 2466f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell } 2467f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell if (volume != mVolume) { 2468f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell mVolume = volume; 2469f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell dispatchRouteVolumeChanged(this); 2470f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell } 2471f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell } 2472f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell 2473d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell @Override 2474d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell void routeUpdated() { 2475d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell int types = 0; 2476d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell final int count = mRoutes.size(); 2477b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell if (count == 0) { 2478b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell // Don't keep empty groups in the router. 247969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown MediaRouter.removeRouteStatic(this); 2480b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell return; 2481b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell } 2482b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell 24838e37a85bf3dc39519942698dc90a3951306b934bAdam Powell int maxVolume = 0; 24848e37a85bf3dc39519942698dc90a3951306b934bAdam Powell boolean isLocal = true; 24858e37a85bf3dc39519942698dc90a3951306b934bAdam Powell boolean isFixedVolume = true; 2486d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell for (int i = 0; i < count; i++) { 24878e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final RouteInfo route = mRoutes.get(i); 24888e37a85bf3dc39519942698dc90a3951306b934bAdam Powell types |= route.mSupportedTypes; 24898e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final int routeMaxVolume = route.getVolumeMax(); 24908e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (routeMaxVolume > maxVolume) { 24918e37a85bf3dc39519942698dc90a3951306b934bAdam Powell maxVolume = routeMaxVolume; 24928e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 24938e37a85bf3dc39519942698dc90a3951306b934bAdam Powell isLocal &= route.getPlaybackType() == PLAYBACK_TYPE_LOCAL; 24948e37a85bf3dc39519942698dc90a3951306b934bAdam Powell isFixedVolume &= route.getVolumeHandling() == PLAYBACK_VOLUME_FIXED; 2495d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell } 24968e37a85bf3dc39519942698dc90a3951306b934bAdam Powell mPlaybackType = isLocal ? PLAYBACK_TYPE_LOCAL : PLAYBACK_TYPE_REMOTE; 24978e37a85bf3dc39519942698dc90a3951306b934bAdam Powell mVolumeHandling = isFixedVolume ? PLAYBACK_VOLUME_FIXED : PLAYBACK_VOLUME_VARIABLE; 2498d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell mSupportedTypes = types; 24998e37a85bf3dc39519942698dc90a3951306b934bAdam Powell mVolumeMax = maxVolume; 2500d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell mIcon = count == 1 ? mRoutes.get(0).getIconDrawable() : null; 2501d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell super.routeUpdated(); 2502d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell } 2503d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell 25049a1de308cea2d160778fd977825f10a07b49d738Adam Powell void updateName() { 25059a1de308cea2d160778fd977825f10a07b49d738Adam Powell final StringBuilder sb = new StringBuilder(); 25069a1de308cea2d160778fd977825f10a07b49d738Adam Powell final int count = mRoutes.size(); 25079a1de308cea2d160778fd977825f10a07b49d738Adam Powell for (int i = 0; i < count; i++) { 25089a1de308cea2d160778fd977825f10a07b49d738Adam Powell final RouteInfo info = mRoutes.get(i); 2509b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell // TODO: There's probably a much more correct way to localize this. 25109a1de308cea2d160778fd977825f10a07b49d738Adam Powell if (i > 0) sb.append(", "); 25119a1de308cea2d160778fd977825f10a07b49d738Adam Powell sb.append(info.mName); 25129a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 25139a1de308cea2d160778fd977825f10a07b49d738Adam Powell mName = sb.toString(); 25149a1de308cea2d160778fd977825f10a07b49d738Adam Powell mUpdateName = false; 25159a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 2516d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell 2517d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell @Override 2518d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell public String toString() { 2519d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell StringBuilder sb = new StringBuilder(super.toString()); 2520d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell sb.append('['); 2521d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell final int count = mRoutes.size(); 2522d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell for (int i = 0; i < count; i++) { 2523d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell if (i > 0) sb.append(", "); 2524d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell sb.append(mRoutes.get(i)); 2525d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell } 2526d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell sb.append(']'); 2527d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell return sb.toString(); 2528d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell } 25299a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 25309a1de308cea2d160778fd977825f10a07b49d738Adam Powell 25319a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 25329a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Definition of a category of routes. All routes belong to a category. 25339a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 2534b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn public static class RouteCategory { 25359a1de308cea2d160778fd977825f10a07b49d738Adam Powell CharSequence mName; 25360d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell int mNameResId; 25379a1de308cea2d160778fd977825f10a07b49d738Adam Powell int mTypes; 25389a1de308cea2d160778fd977825f10a07b49d738Adam Powell final boolean mGroupable; 2539705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell boolean mIsSystem; 25409a1de308cea2d160778fd977825f10a07b49d738Adam Powell 25419a1de308cea2d160778fd977825f10a07b49d738Adam Powell RouteCategory(CharSequence name, int types, boolean groupable) { 25429a1de308cea2d160778fd977825f10a07b49d738Adam Powell mName = name; 25439a1de308cea2d160778fd977825f10a07b49d738Adam Powell mTypes = types; 25449a1de308cea2d160778fd977825f10a07b49d738Adam Powell mGroupable = groupable; 25459a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 25469a1de308cea2d160778fd977825f10a07b49d738Adam Powell 25470d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell RouteCategory(int nameResId, int types, boolean groupable) { 25480d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell mNameResId = nameResId; 25490d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell mTypes = types; 25500d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell mGroupable = groupable; 25510d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell } 25520d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell 25539a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 25549a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @return the name of this route category 25559a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 25569a1de308cea2d160778fd977825f10a07b49d738Adam Powell public CharSequence getName() { 25570d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell return getName(sStatic.mResources); 25580d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell } 25595d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik 25600d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell /** 25610d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * Return the properly localized/configuration dependent name of this RouteCategory. 25625d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik * 25630d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * @param context Context to resolve name resources 25640d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * @return the name of this route category 25650d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell */ 25660d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public CharSequence getName(Context context) { 25670d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell return getName(context.getResources()); 25680d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell } 25695d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik 25700d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell CharSequence getName(Resources res) { 25710d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell if (mNameResId != 0) { 25720d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell return res.getText(mNameResId); 25730d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell } 25749a1de308cea2d160778fd977825f10a07b49d738Adam Powell return mName; 25759a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 25769a1de308cea2d160778fd977825f10a07b49d738Adam Powell 25779a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 2578d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * Return the current list of routes in this category that have been added 2579d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * to the MediaRouter. 25809a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 2581d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * <p>This list will not include routes that are nested within RouteGroups. 2582d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * A RouteGroup is treated as a single route within its category.</p> 2583d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * 2584d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param out a List to fill with the routes in this category. If this parameter is 2585d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * non-null, it will be cleared, filled with the current routes with this 2586d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * category, and returned. If this parameter is null, a new List will be 2587d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * allocated to report the category's current routes. 2588d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @return A list with the routes in this category that have been added to the MediaRouter. 25899a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 2590d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell public List<RouteInfo> getRoutes(List<RouteInfo> out) { 2591d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell if (out == null) { 2592d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell out = new ArrayList<RouteInfo>(); 2593d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell } else { 2594d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell out.clear(); 2595d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell } 2596d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell 2597b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn final int count = getRouteCountStatic(); 2598d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell for (int i = 0; i < count; i++) { 2599b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn final RouteInfo route = getRouteAtStatic(i); 2600d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell if (route.mCategory == this) { 2601d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell out.add(route); 2602d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell } 2603d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell } 2604d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell return out; 26059a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 26069a1de308cea2d160778fd977825f10a07b49d738Adam Powell 26079a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 26089a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @return Flag set describing the route types supported by this category 26099a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 26109a1de308cea2d160778fd977825f10a07b49d738Adam Powell public int getSupportedTypes() { 26119a1de308cea2d160778fd977825f10a07b49d738Adam Powell return mTypes; 26129a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 26139a1de308cea2d160778fd977825f10a07b49d738Adam Powell 26149a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 26159a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Return whether or not this category supports grouping. 26169a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 26179a1de308cea2d160778fd977825f10a07b49d738Adam Powell * <p>If this method returns true, all routes obtained from this category 2618d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * via calls to {@link #getRouteAt(int)} will be {@link MediaRouter.RouteGroup}s.</p> 26199a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 26209a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @return true if this category supports 26219a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 26229a1de308cea2d160778fd977825f10a07b49d738Adam Powell public boolean isGroupable() { 26239a1de308cea2d160778fd977825f10a07b49d738Adam Powell return mGroupable; 26249a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 26259a1de308cea2d160778fd977825f10a07b49d738Adam Powell 2626705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell /** 2627705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell * @return true if this is the category reserved for system routes. 2628705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell * @hide 2629705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell */ 2630705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell public boolean isSystem() { 2631705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell return mIsSystem; 2632705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 2633705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 263469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown @Override 26359a1de308cea2d160778fd977825f10a07b49d738Adam Powell public String toString() { 26369a1de308cea2d160778fd977825f10a07b49d738Adam Powell return "RouteCategory{ name=" + mName + " types=" + typesToString(mTypes) + 2637d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell " groupable=" + mGroupable + " }"; 26389a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 26399a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 26409a1de308cea2d160778fd977825f10a07b49d738Adam Powell 26419a1de308cea2d160778fd977825f10a07b49d738Adam Powell static class CallbackInfo { 26429a1de308cea2d160778fd977825f10a07b49d738Adam Powell public int type; 264366f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown public int flags; 2644b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn public final Callback cb; 2645b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn public final MediaRouter router; 26469a1de308cea2d160778fd977825f10a07b49d738Adam Powell 264766f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown public CallbackInfo(Callback cb, int type, int flags, MediaRouter router) { 26489a1de308cea2d160778fd977825f10a07b49d738Adam Powell this.cb = cb; 26499a1de308cea2d160778fd977825f10a07b49d738Adam Powell this.type = type; 265066f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown this.flags = flags; 2651b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn this.router = router; 26529a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 265366f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown 265466f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown public boolean filterRouteEvent(RouteInfo route) { 2655af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown return filterRouteEvent(route.mSupportedTypes); 2656af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown } 2657af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown 2658af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown public boolean filterRouteEvent(int supportedTypes) { 265966f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown return (flags & CALLBACK_FLAG_UNFILTERED_EVENTS) != 0 2660af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown || (type & supportedTypes) != 0; 266166f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown } 26629a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 26639a1de308cea2d160778fd977825f10a07b49d738Adam Powell 26649a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 26659a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Interface for receiving events about media routing changes. 26669a1de308cea2d160778fd977825f10a07b49d738Adam Powell * All methods of this interface will be called from the application's main thread. 266766f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * <p> 266866f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * A Callback will only receive events relevant to routes that the callback 266966f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * was registered for unless the {@link MediaRouter#CALLBACK_FLAG_UNFILTERED_EVENTS} 267066f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * flag was specified in {@link MediaRouter#addCallback(int, Callback, int)}. 267166f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * </p> 26729a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 267366f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * @see MediaRouter#addCallback(int, Callback, int) 26749a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @see MediaRouter#removeCallback(Callback) 26759a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 26760d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public static abstract class Callback { 26779a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 26789a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Called when the supplied route becomes selected as the active route 26799a1de308cea2d160778fd977825f10a07b49d738Adam Powell * for the given route type. 26809a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 2681d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param router the MediaRouter reporting the event 26829a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param type Type flag set indicating the routes that have been selected 26839a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param info Route that has been selected for the given route types 26849a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 26850d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public abstract void onRouteSelected(MediaRouter router, int type, RouteInfo info); 26869a1de308cea2d160778fd977825f10a07b49d738Adam Powell 26879a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 26889a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Called when the supplied route becomes unselected as the active route 26899a1de308cea2d160778fd977825f10a07b49d738Adam Powell * for the given route type. 26909a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 2691d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param router the MediaRouter reporting the event 26929a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param type Type flag set indicating the routes that have been unselected 26939a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param info Route that has been unselected for the given route types 26949a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 26950d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public abstract void onRouteUnselected(MediaRouter router, int type, RouteInfo info); 26969a1de308cea2d160778fd977825f10a07b49d738Adam Powell 26979a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 26989a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Called when a route for the specified type was added. 26999a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 2700d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param router the MediaRouter reporting the event 27019a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param info Route that has become available for use 27029a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 27030d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public abstract void onRouteAdded(MediaRouter router, RouteInfo info); 27049a1de308cea2d160778fd977825f10a07b49d738Adam Powell 27059a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 27069a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Called when a route for the specified type was removed. 27079a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 2708d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param router the MediaRouter reporting the event 27099a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param info Route that has been removed from availability 27109a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 27110d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public abstract void onRouteRemoved(MediaRouter router, RouteInfo info); 27129a1de308cea2d160778fd977825f10a07b49d738Adam Powell 27139a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 27149a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Called when an aspect of the indicated route has changed. 27159a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 27169a1de308cea2d160778fd977825f10a07b49d738Adam Powell * <p>This will not indicate that the types supported by this route have 27179a1de308cea2d160778fd977825f10a07b49d738Adam Powell * changed, only that cosmetic info such as name or status have been updated.</p> 27189a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 2719d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param router the MediaRouter reporting the event 27209a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param info The route that was changed 27219a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 27220d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public abstract void onRouteChanged(MediaRouter router, RouteInfo info); 2723d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell 2724d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell /** 2725d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * Called when a route is added to a group. 2726d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * 2727d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param router the MediaRouter reporting the event 2728d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param info The route that was added 2729d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param group The group the route was added to 2730d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param index The route index within group that info was added at 2731d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell */ 27320d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public abstract void onRouteGrouped(MediaRouter router, RouteInfo info, RouteGroup group, 27330d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell int index); 2734d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell 2735d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell /** 2736d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * Called when a route is removed from a group. 2737d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * 2738d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param router the MediaRouter reporting the event 2739d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param info The route that was removed 2740d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param group The group the route was removed from 2741d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell */ 27420d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public abstract void onRouteUngrouped(MediaRouter router, RouteInfo info, RouteGroup group); 27438e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 27448e37a85bf3dc39519942698dc90a3951306b934bAdam Powell /** 27458e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * Called when a route's volume changes. 27468e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * 27478e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * @param router the MediaRouter reporting the event 27488e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * @param info The route with altered volume 27498e37a85bf3dc39519942698dc90a3951306b934bAdam Powell */ 27508e37a85bf3dc39519942698dc90a3951306b934bAdam Powell public abstract void onRouteVolumeChanged(MediaRouter router, RouteInfo info); 275192130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown 275292130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown /** 275392130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * Called when a route's presentation display changes. 275492130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * <p> 275592130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * This method is called whenever the route's presentation display becomes 275692130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * available, is removes or has changes to some of its properties (such as its size). 275792130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * </p> 275892130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * 275992130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * @param router the MediaRouter reporting the event 276092130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * @param info The route whose presentation display changed 276192130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * 276292130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * @see RouteInfo#getPresentationDisplay() 276392130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown */ 276492130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown public void onRoutePresentationDisplayChanged(MediaRouter router, RouteInfo info) { 276592130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown } 27669a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 27679a1de308cea2d160778fd977825f10a07b49d738Adam Powell 27689a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 27690d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * Stub implementation of {@link MediaRouter.Callback}. 27700d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * Each abstract method is defined as a no-op. Override just the ones 27719a1de308cea2d160778fd977825f10a07b49d738Adam Powell * you need. 27729a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 27730d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public static class SimpleCallback extends Callback { 27749a1de308cea2d160778fd977825f10a07b49d738Adam Powell 27759a1de308cea2d160778fd977825f10a07b49d738Adam Powell @Override 2776d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell public void onRouteSelected(MediaRouter router, int type, RouteInfo info) { 27779a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 27789a1de308cea2d160778fd977825f10a07b49d738Adam Powell 27799a1de308cea2d160778fd977825f10a07b49d738Adam Powell @Override 2780d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell public void onRouteUnselected(MediaRouter router, int type, RouteInfo info) { 27819a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 27829a1de308cea2d160778fd977825f10a07b49d738Adam Powell 27839a1de308cea2d160778fd977825f10a07b49d738Adam Powell @Override 2784d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell public void onRouteAdded(MediaRouter router, RouteInfo info) { 27859a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 27869a1de308cea2d160778fd977825f10a07b49d738Adam Powell 27879a1de308cea2d160778fd977825f10a07b49d738Adam Powell @Override 2788d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell public void onRouteRemoved(MediaRouter router, RouteInfo info) { 27899a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 27909a1de308cea2d160778fd977825f10a07b49d738Adam Powell 27919a1de308cea2d160778fd977825f10a07b49d738Adam Powell @Override 2792d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell public void onRouteChanged(MediaRouter router, RouteInfo info) { 27939a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 27949a1de308cea2d160778fd977825f10a07b49d738Adam Powell 27959a1de308cea2d160778fd977825f10a07b49d738Adam Powell @Override 2796d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell public void onRouteGrouped(MediaRouter router, RouteInfo info, RouteGroup group, 2797d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell int index) { 27989a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 27999a1de308cea2d160778fd977825f10a07b49d738Adam Powell 28009a1de308cea2d160778fd977825f10a07b49d738Adam Powell @Override 2801d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell public void onRouteUngrouped(MediaRouter router, RouteInfo info, RouteGroup group) { 28029a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 2803d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell 28048e37a85bf3dc39519942698dc90a3951306b934bAdam Powell @Override 28058e37a85bf3dc39519942698dc90a3951306b934bAdam Powell public void onRouteVolumeChanged(MediaRouter router, RouteInfo info) { 28068e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 28079a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 28081357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 28091357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi static class VolumeCallbackInfo { 28101357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public final VolumeCallback vcb; 28111357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public final RouteInfo route; 28121357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 28131357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public VolumeCallbackInfo(VolumeCallback vcb, RouteInfo route) { 28141357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi this.vcb = vcb; 28151357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi this.route = route; 28161357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 28171357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 28181357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 28191357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 28201357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * Interface for receiving events about volume changes. 28211357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * All methods of this interface will be called from the application's main thread. 28221357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * 28231357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * <p>A VolumeCallback will only receive events relevant to routes that the callback 28241357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * was registered for.</p> 28251357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * 28261357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @see UserRouteInfo#setVolumeCallback(VolumeCallback) 28271357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 28281357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public static abstract class VolumeCallback { 28291357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 28301357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * Called when the volume for the route should be increased or decreased. 28311357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @param info the route affected by this event 28321357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @param direction an integer indicating whether the volume is to be increased 28331357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * (positive value) or decreased (negative value). 28341357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * For bundled changes, the absolute value indicates the number of changes 28351357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * in the same direction, e.g. +3 corresponds to three "volume up" changes. 28361357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 28371357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public abstract void onVolumeUpdateRequest(RouteInfo info, int direction); 28381357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 28391357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * Called when the volume for the route should be set to the given value 28401357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @param info the route affected by this event 28411357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @param volume an integer indicating the new volume value that should be used, always 28421357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * between 0 and the value set by {@link UserRouteInfo#setVolumeMax(int)}. 28431357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 28441357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public abstract void onVolumeSetRequest(RouteInfo info, int volume); 28451357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 28461357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 28478e37a85bf3dc39519942698dc90a3951306b934bAdam Powell static class VolumeChangeReceiver extends BroadcastReceiver { 28488e37a85bf3dc39519942698dc90a3951306b934bAdam Powell @Override 28498e37a85bf3dc39519942698dc90a3951306b934bAdam Powell public void onReceive(Context context, Intent intent) { 28508e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (intent.getAction().equals(AudioManager.VOLUME_CHANGED_ACTION)) { 28518e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final int streamType = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, 28528e37a85bf3dc39519942698dc90a3951306b934bAdam Powell -1); 28538e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (streamType != AudioManager.STREAM_MUSIC) { 28548e37a85bf3dc39519942698dc90a3951306b934bAdam Powell return; 28558e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 28568e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 28578e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final int newVolume = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, 0); 28588e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final int oldVolume = intent.getIntExtra( 28598e37a85bf3dc39519942698dc90a3951306b934bAdam Powell AudioManager.EXTRA_PREV_VOLUME_STREAM_VALUE, 0); 28608e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (newVolume != oldVolume) { 28618e37a85bf3dc39519942698dc90a3951306b934bAdam Powell systemVolumeChanged(newVolume); 28628e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 28638e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 28648e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 2865705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 28668e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 2867705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell static class WifiDisplayStatusChangedReceiver extends BroadcastReceiver { 2868705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell @Override 2869705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell public void onReceive(Context context, Intent intent) { 2870705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell if (intent.getAction().equals(DisplayManager.ACTION_WIFI_DISPLAY_STATUS_CHANGED)) { 2871705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell updateWifiDisplayStatus((WifiDisplayStatus) intent.getParcelableExtra( 2872705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell DisplayManager.EXTRA_WIFI_DISPLAY_STATUS)); 2873705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 2874705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 28758e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 28769a1de308cea2d160778fd977825f10a07b49d738Adam Powell} 2877