MediaRouter.java revision 0d0f67f5ee5f939a1b611bc4583212707afd9bee
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 193705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell if (!TextUtils.equals(newRoutes.mBluetoothName, mCurAudioRoutesInfo.mBluetoothName)) { 194705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell mCurAudioRoutesInfo.mBluetoothName = newRoutes.mBluetoothName; 195705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell if (mCurAudioRoutesInfo.mBluetoothName != null) { 196632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn if (sStatic.mBluetoothA2dpRoute == null) { 197632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn final RouteInfo info = new RouteInfo(sStatic.mSystemCategory); 198705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell info.mName = mCurAudioRoutesInfo.mBluetoothName; 19956d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown info.mDescription = sStatic.mResources.getText( 20056d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown com.android.internal.R.string.bluetooth_a2dp_audio_route_name); 201632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn info.mSupportedTypes = ROUTE_TYPE_LIVE_AUDIO; 202632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn sStatic.mBluetoothA2dpRoute = info; 2032ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell addRouteStatic(sStatic.mBluetoothA2dpRoute); 204632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } else { 205705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell sStatic.mBluetoothA2dpRoute.mName = mCurAudioRoutesInfo.mBluetoothName; 206632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn dispatchRouteChanged(sStatic.mBluetoothA2dpRoute); 207632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } 208632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } else if (sStatic.mBluetoothA2dpRoute != null) { 20969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown removeRouteStatic(sStatic.mBluetoothA2dpRoute); 210632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn sStatic.mBluetoothA2dpRoute = null; 211632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } 212632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } 213bcf21e913af7252fb1994e07b6cf179321ecd049Adam Powell 214bcf21e913af7252fb1994e07b6cf179321ecd049Adam Powell if (mBluetoothA2dpRoute != null) { 215f1b2335a36fa6f2b9926f309a7c4ed29a1404ec4Jeff Brown final boolean a2dpEnabled = isBluetoothA2dpOn(); 2163f369684e13dfea0ba8ea134f3e95930b0dd7df0Adam Powell if (mainType != AudioRoutesInfo.MAIN_SPEAKER && 2173f369684e13dfea0ba8ea134f3e95930b0dd7df0Adam Powell mSelectedRoute == mBluetoothA2dpRoute && !a2dpEnabled) { 21869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown selectRouteStatic(ROUTE_TYPE_LIVE_AUDIO, mDefaultAudioVideo, false); 2193f369684e13dfea0ba8ea134f3e95930b0dd7df0Adam Powell } else if ((mSelectedRoute == mDefaultAudioVideo || mSelectedRoute == null) && 2202ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell a2dpEnabled) { 22169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown selectRouteStatic(ROUTE_TYPE_LIVE_AUDIO, mBluetoothA2dpRoute, false); 222bcf21e913af7252fb1994e07b6cf179321ecd049Adam Powell } 223bcf21e913af7252fb1994e07b6cf179321ecd049Adam Powell } 224b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn } 22592130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown 226f1b2335a36fa6f2b9926f309a7c4ed29a1404ec4Jeff Brown boolean isBluetoothA2dpOn() { 227f1b2335a36fa6f2b9926f309a7c4ed29a1404ec4Jeff Brown try { 228f1b2335a36fa6f2b9926f309a7c4ed29a1404ec4Jeff Brown return mAudioService.isBluetoothA2dpOn(); 229f1b2335a36fa6f2b9926f309a7c4ed29a1404ec4Jeff Brown } catch (RemoteException e) { 230f1b2335a36fa6f2b9926f309a7c4ed29a1404ec4Jeff Brown Log.e(TAG, "Error querying Bluetooth A2DP state", e); 231f1b2335a36fa6f2b9926f309a7c4ed29a1404ec4Jeff Brown return false; 232f1b2335a36fa6f2b9926f309a7c4ed29a1404ec4Jeff Brown } 233f1b2335a36fa6f2b9926f309a7c4ed29a1404ec4Jeff Brown } 234f1b2335a36fa6f2b9926f309a7c4ed29a1404ec4Jeff Brown 23569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown void updateDiscoveryRequest() { 23669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // What are we looking for today? 23769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown int routeTypes = 0; 23869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown int passiveRouteTypes = 0; 23969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown boolean activeScan = false; 24069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown boolean activeScanWifiDisplay = false; 24169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final int count = mCallbacks.size(); 24269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown for (int i = 0; i < count; i++) { 24369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown CallbackInfo cbi = mCallbacks.get(i); 24469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if ((cbi.flags & (CALLBACK_FLAG_PERFORM_ACTIVE_SCAN 24569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown | CALLBACK_FLAG_REQUEST_DISCOVERY)) != 0) { 24669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Discovery explicitly requested. 24769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown routeTypes |= cbi.type; 24869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } else if ((cbi.flags & CALLBACK_FLAG_PASSIVE_DISCOVERY) != 0) { 24969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Discovery only passively requested. 25069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown passiveRouteTypes |= cbi.type; 25169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } else { 25269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Legacy case since applications don't specify the discovery flag. 25369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Unfortunately we just have to assume they always need discovery 25469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // whenever they have a callback registered. 25569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown routeTypes |= cbi.type; 25669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 25769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if ((cbi.flags & CALLBACK_FLAG_PERFORM_ACTIVE_SCAN) != 0) { 25869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown activeScan = true; 259af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown if ((cbi.type & ROUTE_TYPE_REMOTE_DISPLAY) != 0) { 26069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown activeScanWifiDisplay = true; 26169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 26269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 26369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 26469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (routeTypes != 0 || activeScan) { 26569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // If someone else requests discovery then enable the passive listeners. 26669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // This is used by the MediaRouteButton and MediaRouteActionProvider since 26769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // they don't receive lifecycle callbacks from the Activity. 26869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown routeTypes |= passiveRouteTypes; 26969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 27069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 27169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Update wifi display scanning. 272ce468a35b388ca46578934706b38dbae94941643Jeff Brown // TODO: All of this should be managed by the media router service. 273ce468a35b388ca46578934706b38dbae94941643Jeff Brown if (mCanConfigureWifiDisplays) { 274ce468a35b388ca46578934706b38dbae94941643Jeff Brown if (mSelectedRoute != null 275ce468a35b388ca46578934706b38dbae94941643Jeff Brown && mSelectedRoute.matchesTypes(ROUTE_TYPE_REMOTE_DISPLAY)) { 276ce468a35b388ca46578934706b38dbae94941643Jeff Brown // Don't scan while already connected to a remote display since 277ce468a35b388ca46578934706b38dbae94941643Jeff Brown // it may interfere with the ongoing transmission. 278ce468a35b388ca46578934706b38dbae94941643Jeff Brown activeScanWifiDisplay = false; 27966f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown } 280ce468a35b388ca46578934706b38dbae94941643Jeff Brown if (activeScanWifiDisplay) { 281ce468a35b388ca46578934706b38dbae94941643Jeff Brown if (!mActivelyScanningWifiDisplays) { 282ce468a35b388ca46578934706b38dbae94941643Jeff Brown mActivelyScanningWifiDisplays = true; 283ce468a35b388ca46578934706b38dbae94941643Jeff Brown mDisplayService.startWifiDisplayScan(); 284ce468a35b388ca46578934706b38dbae94941643Jeff Brown } 285ce468a35b388ca46578934706b38dbae94941643Jeff Brown } else { 286ce468a35b388ca46578934706b38dbae94941643Jeff Brown if (mActivelyScanningWifiDisplays) { 287ce468a35b388ca46578934706b38dbae94941643Jeff Brown mActivelyScanningWifiDisplays = false; 288ce468a35b388ca46578934706b38dbae94941643Jeff Brown mDisplayService.stopWifiDisplayScan(); 289ce468a35b388ca46578934706b38dbae94941643Jeff Brown } 29066f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown } 29166f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown } 29266f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown 29369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Tell the media router service all about it. 29469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (routeTypes != mDiscoveryRequestRouteTypes 29569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown || activeScan != mDiscoverRequestActiveScan) { 29669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mDiscoveryRequestRouteTypes = routeTypes; 29769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mDiscoverRequestActiveScan = activeScan; 29869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown publishClientDiscoveryRequest(); 29966f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown } 30066f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown } 30166f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown 30292130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown @Override 30392130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown public void onDisplayAdded(int displayId) { 30492130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown updatePresentationDisplays(displayId); 30592130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown } 30692130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown 30792130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown @Override 30892130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown public void onDisplayChanged(int displayId) { 30992130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown updatePresentationDisplays(displayId); 31092130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown } 31192130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown 31292130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown @Override 31392130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown public void onDisplayRemoved(int displayId) { 31492130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown updatePresentationDisplays(displayId); 31592130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown } 31692130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown 31792130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown public Display[] getAllPresentationDisplays() { 31892130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown return mDisplayService.getDisplays(DisplayManager.DISPLAY_CATEGORY_PRESENTATION); 31992130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown } 32092130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown 32192130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown private void updatePresentationDisplays(int changedDisplayId) { 32292130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown final int count = mRoutes.size(); 32392130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown for (int i = 0; i < count; i++) { 3245830b0b33618940d65197cec99d697b21908fec8Chong Zhang final RouteInfo route = mRoutes.get(i); 3255830b0b33618940d65197cec99d697b21908fec8Chong Zhang if (route.updatePresentationDisplay() || (route.mPresentationDisplay != null 3265830b0b33618940d65197cec99d697b21908fec8Chong Zhang && route.mPresentationDisplay.getDisplayId() == changedDisplayId)) { 3275830b0b33618940d65197cec99d697b21908fec8Chong Zhang dispatchRoutePresentationDisplayChanged(route); 32892130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown } 32992130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown } 33092130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown } 33169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 33269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown void setSelectedRoute(RouteInfo info, boolean explicit) { 33369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Must be non-reentrant. 33469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mSelectedRoute = info; 33569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown publishClientSelectedRoute(explicit); 33669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 33769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 33869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown void rebindAsUser(int userId) { 33969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (mCurrentUserId != userId || userId < 0 || mClient == null) { 34069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (mClient != null) { 34169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown try { 34269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mMediaRouterService.unregisterClient(mClient); 34369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } catch (RemoteException ex) { 34469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Log.e(TAG, "Unable to unregister media router client.", ex); 34569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 34669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mClient = null; 34769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 34869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 34969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mCurrentUserId = userId; 35069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 35169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown try { 35269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Client client = new Client(); 35369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mMediaRouterService.registerClientAsUser(client, 35469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mAppContext.getPackageName(), userId); 35569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mClient = client; 35669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } catch (RemoteException ex) { 35769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Log.e(TAG, "Unable to register media router client.", ex); 35869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 35969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 36069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown publishClientDiscoveryRequest(); 36169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown publishClientSelectedRoute(false); 36269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown updateClientState(); 36369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 36469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 36569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 36669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown void publishClientDiscoveryRequest() { 36769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (mClient != null) { 36869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown try { 36969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mMediaRouterService.setDiscoveryRequest(mClient, 37069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mDiscoveryRequestRouteTypes, mDiscoverRequestActiveScan); 37169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } catch (RemoteException ex) { 37269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Log.e(TAG, "Unable to publish media router client discovery request.", ex); 37369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 37469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 37569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 37669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 37769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown void publishClientSelectedRoute(boolean explicit) { 37869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (mClient != null) { 37969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown try { 38069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mMediaRouterService.setSelectedRoute(mClient, 38169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mSelectedRoute != null ? mSelectedRoute.mGlobalRouteId : null, 38269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown explicit); 38369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } catch (RemoteException ex) { 38469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Log.e(TAG, "Unable to publish media router client selected route.", ex); 38569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 38669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 38769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 38869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 38969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown void updateClientState() { 39069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Update the client state. 39169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mClientState = null; 39269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (mClient != null) { 39369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown try { 39469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mClientState = mMediaRouterService.getState(mClient); 39569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } catch (RemoteException ex) { 39669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Log.e(TAG, "Unable to retrieve media router client state.", ex); 39769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 39869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 39969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final ArrayList<MediaRouterClientState.RouteInfo> globalRoutes = 40069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mClientState != null ? mClientState.routes : null; 40169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final String globallySelectedRouteId = mClientState != null ? 40269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mClientState.globallySelectedRouteId : null; 40369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 40469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Add or update routes. 40569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final int globalRouteCount = globalRoutes != null ? globalRoutes.size() : 0; 40669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown for (int i = 0; i < globalRouteCount; i++) { 40769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final MediaRouterClientState.RouteInfo globalRoute = globalRoutes.get(i); 40869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown RouteInfo route = findGlobalRoute(globalRoute.id); 40969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (route == null) { 41069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route = makeGlobalRoute(globalRoute); 41169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown addRouteStatic(route); 41269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } else { 41369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown updateGlobalRoute(route, globalRoute); 41469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 41569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 41669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 41769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Synchronize state with the globally selected route. 41869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (globallySelectedRouteId != null) { 41969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final RouteInfo route = findGlobalRoute(globallySelectedRouteId); 42069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (route == null) { 42169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Log.w(TAG, "Could not find new globally selected route: " 42269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown + globallySelectedRouteId); 42369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } else if (route != mSelectedRoute) { 42469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (DEBUG) { 42569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Log.d(TAG, "Selecting new globally selected route: " + route); 42669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 42769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown selectRouteStatic(route.mSupportedTypes, route, false); 42869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 42969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } else if (mSelectedRoute != null && mSelectedRoute.mGlobalRouteId != null) { 43069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (DEBUG) { 43169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Log.d(TAG, "Unselecting previous globally selected route: " + mSelectedRoute); 43269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 43369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown selectDefaultRouteStatic(); 43469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 43569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 43669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Remove defunct routes. 43769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown outer: for (int i = mRoutes.size(); i-- > 0; ) { 43869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final RouteInfo route = mRoutes.get(i); 43969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final String globalRouteId = route.mGlobalRouteId; 44069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (globalRouteId != null) { 44169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown for (int j = 0; j < globalRouteCount; j++) { 44269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown MediaRouterClientState.RouteInfo globalRoute = globalRoutes.get(j); 44369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (globalRouteId.equals(globalRoute.id)) { 44469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown continue outer; // found 44569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 44669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 44769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // not found 44869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown removeRouteStatic(route); 44969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 45069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 45169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 45269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 45369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown void requestSetVolume(RouteInfo route, int volume) { 45469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (route.mGlobalRouteId != null && mClient != null) { 45569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown try { 45669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mMediaRouterService.requestSetVolume(mClient, 45769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mGlobalRouteId, volume); 45869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } catch (RemoteException ex) { 45969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Log.w(TAG, "Unable to request volume change.", ex); 46069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 46169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 46269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 46369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 46469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown void requestUpdateVolume(RouteInfo route, int direction) { 46569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (route.mGlobalRouteId != null && mClient != null) { 46669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown try { 46769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mMediaRouterService.requestUpdateVolume(mClient, 46869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mGlobalRouteId, direction); 46969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } catch (RemoteException ex) { 47069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Log.w(TAG, "Unable to request volume change.", ex); 47169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 47269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 47369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 47469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 47569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown RouteInfo makeGlobalRoute(MediaRouterClientState.RouteInfo globalRoute) { 47669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown RouteInfo route = new RouteInfo(sStatic.mSystemCategory); 47769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mGlobalRouteId = globalRoute.id; 47869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mName = globalRoute.name; 47969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mDescription = globalRoute.description; 48069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mSupportedTypes = globalRoute.supportedTypes; 48169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mEnabled = globalRoute.enabled; 48239ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown route.setRealStatusCode(globalRoute.statusCode); 48369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mPlaybackType = globalRoute.playbackType; 48469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mPlaybackStream = globalRoute.playbackStream; 48569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mVolume = globalRoute.volume; 48669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mVolumeMax = globalRoute.volumeMax; 48769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mVolumeHandling = globalRoute.volumeHandling; 4885830b0b33618940d65197cec99d697b21908fec8Chong Zhang route.mPresentationDisplayId = globalRoute.presentationDisplayId; 4895830b0b33618940d65197cec99d697b21908fec8Chong Zhang route.updatePresentationDisplay(); 49069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return route; 49169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 49269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 49369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown void updateGlobalRoute(RouteInfo route, MediaRouterClientState.RouteInfo globalRoute) { 49469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown boolean changed = false; 49569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown boolean volumeChanged = false; 49669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown boolean presentationDisplayChanged = false; 49769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 498e6585b32ea586743258a5457e2184ffc087f2d2fKenny Root if (!Objects.equals(route.mName, globalRoute.name)) { 49969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mName = globalRoute.name; 50069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown changed = true; 50169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 502e6585b32ea586743258a5457e2184ffc087f2d2fKenny Root if (!Objects.equals(route.mDescription, globalRoute.description)) { 50369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mDescription = globalRoute.description; 50469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown changed = true; 50569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 506af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown final int oldSupportedTypes = route.mSupportedTypes; 507af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown if (oldSupportedTypes != globalRoute.supportedTypes) { 50869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mSupportedTypes = globalRoute.supportedTypes; 50969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown changed = true; 51069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 51169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (route.mEnabled != globalRoute.enabled) { 51269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mEnabled = globalRoute.enabled; 51369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown changed = true; 51469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 51539ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown if (route.mRealStatusCode != globalRoute.statusCode) { 51639ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown route.setRealStatusCode(globalRoute.statusCode); 51769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown changed = true; 51869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 51969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (route.mPlaybackType != globalRoute.playbackType) { 52069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mPlaybackType = globalRoute.playbackType; 52169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown changed = true; 52269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 52369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (route.mPlaybackStream != globalRoute.playbackStream) { 52469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mPlaybackStream = globalRoute.playbackStream; 52569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown changed = true; 52669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 52769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (route.mVolume != globalRoute.volume) { 52869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mVolume = globalRoute.volume; 52969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown changed = true; 53069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown volumeChanged = true; 53169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 53269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (route.mVolumeMax != globalRoute.volumeMax) { 53369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mVolumeMax = globalRoute.volumeMax; 53469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown changed = true; 53569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown volumeChanged = true; 53669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 53769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (route.mVolumeHandling != globalRoute.volumeHandling) { 53869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mVolumeHandling = globalRoute.volumeHandling; 53969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown changed = true; 54069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown volumeChanged = true; 54169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 5425830b0b33618940d65197cec99d697b21908fec8Chong Zhang if (route.mPresentationDisplayId != globalRoute.presentationDisplayId) { 5435830b0b33618940d65197cec99d697b21908fec8Chong Zhang route.mPresentationDisplayId = globalRoute.presentationDisplayId; 5445830b0b33618940d65197cec99d697b21908fec8Chong Zhang route.updatePresentationDisplay(); 54569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown changed = true; 54669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown presentationDisplayChanged = true; 54769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 54869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 54969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (changed) { 550af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown dispatchRouteChanged(route, oldSupportedTypes); 55169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 55269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (volumeChanged) { 55369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown dispatchRouteVolumeChanged(route); 55469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 55569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (presentationDisplayChanged) { 55669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown dispatchRoutePresentationDisplayChanged(route); 55769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 55869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 55969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 56069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown RouteInfo findGlobalRoute(String globalRouteId) { 56169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final int count = mRoutes.size(); 56269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown for (int i = 0; i < count; i++) { 56369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final RouteInfo route = mRoutes.get(i); 56469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (globalRouteId.equals(route.mGlobalRouteId)) { 56569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return route; 56669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 56769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 56869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return null; 56969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 57069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 57169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final class Client extends IMediaRouterClient.Stub { 57269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown @Override 57369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public void onStateChanged() { 57469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mHandler.post(new Runnable() { 57569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown @Override 57669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public void run() { 57769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (Client.this == mClient) { 57869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown updateClientState(); 57969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 58069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 58169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown }); 58269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 58369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 584b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn } 5859a1de308cea2d160778fd977825f10a07b49d738Adam Powell 586b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn static Static sStatic; 5879a1de308cea2d160778fd977825f10a07b49d738Adam Powell 5889a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 5899a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Route type flag for live audio. 5909a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 5919a1de308cea2d160778fd977825f10a07b49d738Adam Powell * <p>A device that supports live audio routing will allow the media audio stream 5929a1de308cea2d160778fd977825f10a07b49d738Adam Powell * to be routed to supported destinations. This can include internal speakers or 5939a1de308cea2d160778fd977825f10a07b49d738Adam Powell * audio jacks on the device itself, A2DP devices, and more.</p> 5949a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 5959a1de308cea2d160778fd977825f10a07b49d738Adam Powell * <p>Once initiated this routing is transparent to the application. All audio 5969a1de308cea2d160778fd977825f10a07b49d738Adam Powell * played on the media stream will be routed to the selected destination.</p> 5979a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 59869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public static final int ROUTE_TYPE_LIVE_AUDIO = 1 << 0; 5999a1de308cea2d160778fd977825f10a07b49d738Adam Powell 6009a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 601705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell * Route type flag for live video. 602705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell * 603705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell * <p>A device that supports live video routing will allow a mirrored version 604705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell * of the device's primary display or a customized 605705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell * {@link android.app.Presentation Presentation} to be routed to supported destinations.</p> 606705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell * 607705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell * <p>Once initiated, display mirroring is transparent to the application. 608705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell * While remote routing is active the application may use a 609705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell * {@link android.app.Presentation Presentation} to replace the mirrored view 610705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell * on the external display with different content.</p> 61192130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * 61292130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * @see RouteInfo#getPresentationDisplay() 61392130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * @see android.app.Presentation 614705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell */ 61569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public static final int ROUTE_TYPE_LIVE_VIDEO = 1 << 1; 61669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 61769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown /** 61869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * Temporary interop constant to identify remote displays. 61969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * @hide To be removed when media router API is updated. 62069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown */ 62169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public static final int ROUTE_TYPE_REMOTE_DISPLAY = 1 << 2; 622705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 623705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell /** 6249a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Route type flag for application-specific usage. 6259a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 6269a1de308cea2d160778fd977825f10a07b49d738Adam Powell * <p>Unlike other media route types, user routes are managed by the application. 6279a1de308cea2d160778fd977825f10a07b49d738Adam Powell * The MediaRouter will manage and dispatch events for user routes, but the application 6289a1de308cea2d160778fd977825f10a07b49d738Adam Powell * is expected to interpret the meaning of these events and perform the requested 6299a1de308cea2d160778fd977825f10a07b49d738Adam Powell * routing tasks.</p> 6309a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 63169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public static final int ROUTE_TYPE_USER = 1 << 23; 63269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 63369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown static final int ROUTE_TYPE_ANY = ROUTE_TYPE_LIVE_AUDIO | ROUTE_TYPE_LIVE_VIDEO 63469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown | ROUTE_TYPE_REMOTE_DISPLAY | ROUTE_TYPE_USER; 6359a1de308cea2d160778fd977825f10a07b49d738Adam Powell 63666f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown /** 63766f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * Flag for {@link #addCallback}: Actively scan for routes while this callback 63866f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * is registered. 63966f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * <p> 64066f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * When this flag is specified, the media router will actively scan for new 64166f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * routes. Certain routes, such as wifi display routes, may not be discoverable 64266f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * except when actively scanning. This flag is typically used when the route picker 64366f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * dialog has been opened by the user to ensure that the route information is 64466f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * up to date. 64566f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * </p><p> 64666f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * Active scanning may consume a significant amount of power and may have intrusive 64766f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * effects on wireless connectivity. Therefore it is important that active scanning 64866f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * only be requested when it is actually needed to satisfy a user request to 64966f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * discover and select a new route. 65066f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * </p> 65166f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown */ 65214507e257af5d71577574e25cbd690c4b54c9272Jeff Brown public static final int CALLBACK_FLAG_PERFORM_ACTIVE_SCAN = 1 << 0; 65366f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown 65466f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown /** 65566f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * Flag for {@link #addCallback}: Do not filter route events. 65666f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * <p> 65766f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * When this flag is specified, the callback will be invoked for event that affect any 65869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * route even if they do not match the callback's filter. 65966f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * </p> 66066f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown */ 66166f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown public static final int CALLBACK_FLAG_UNFILTERED_EVENTS = 1 << 1; 66266f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown 66369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown /** 66469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * Explicitly requests discovery. 66569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * 66669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * @hide Future API ported from support library. Revisit this later. 66769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown */ 66869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public static final int CALLBACK_FLAG_REQUEST_DISCOVERY = 1 << 2; 66969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 67069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown /** 67169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * Requests that discovery be performed but only if there is some other active 67269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * callback already registered. 67369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * 67469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * @hide Compatibility workaround for the fact that applications do not currently 67569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * request discovery explicitly (except when using the support library API). 67669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown */ 67769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public static final int CALLBACK_FLAG_PASSIVE_DISCOVERY = 1 << 3; 67869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 6790abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown /** 6800abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * Flag for {@link #isRouteAvailable}: Ignore the default route. 6810abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * <p> 6820abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * This flag is used to determine whether a matching non-default route is available. 6830abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * This constraint may be used to decide whether to offer the route chooser dialog 6840abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * to the user. There is no point offering the chooser if there are no 6850abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * non-default choices. 6860abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * </p> 6870abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * 6880abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * @hide Future API ported from support library. Revisit this later. 6890abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown */ 6900abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown public static final int AVAILABILITY_FLAG_IGNORE_DEFAULT_ROUTE = 1 << 0; 6910abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown 6929a1de308cea2d160778fd977825f10a07b49d738Adam Powell // Maps application contexts 6939a1de308cea2d160778fd977825f10a07b49d738Adam Powell static final HashMap<Context, MediaRouter> sRouters = new HashMap<Context, MediaRouter>(); 6949a1de308cea2d160778fd977825f10a07b49d738Adam Powell 6959a1de308cea2d160778fd977825f10a07b49d738Adam Powell static String typesToString(int types) { 6969a1de308cea2d160778fd977825f10a07b49d738Adam Powell final StringBuilder result = new StringBuilder(); 6979a1de308cea2d160778fd977825f10a07b49d738Adam Powell if ((types & ROUTE_TYPE_LIVE_AUDIO) != 0) { 6989a1de308cea2d160778fd977825f10a07b49d738Adam Powell result.append("ROUTE_TYPE_LIVE_AUDIO "); 6999a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 7002bb7c122ef6ce8539dfbaeb3292adcd942185f82Bryan Mawhinney if ((types & ROUTE_TYPE_LIVE_VIDEO) != 0) { 7012bb7c122ef6ce8539dfbaeb3292adcd942185f82Bryan Mawhinney result.append("ROUTE_TYPE_LIVE_VIDEO "); 7022bb7c122ef6ce8539dfbaeb3292adcd942185f82Bryan Mawhinney } 70369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if ((types & ROUTE_TYPE_REMOTE_DISPLAY) != 0) { 70469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown result.append("ROUTE_TYPE_REMOTE_DISPLAY "); 70569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 7069a1de308cea2d160778fd977825f10a07b49d738Adam Powell if ((types & ROUTE_TYPE_USER) != 0) { 7079a1de308cea2d160778fd977825f10a07b49d738Adam Powell result.append("ROUTE_TYPE_USER "); 7089a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 7099a1de308cea2d160778fd977825f10a07b49d738Adam Powell return result.toString(); 7109a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 7119a1de308cea2d160778fd977825f10a07b49d738Adam Powell 712b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn /** @hide */ 713b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn public MediaRouter(Context context) { 714b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn synchronized (Static.class) { 715b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn if (sStatic == null) { 7168e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final Context appContext = context.getApplicationContext(); 7178e37a85bf3dc39519942698dc90a3951306b934bAdam Powell sStatic = new Static(appContext); 7188e37a85bf3dc39519942698dc90a3951306b934bAdam Powell sStatic.startMonitoringRoutes(appContext); 719b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn } 7209a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 7219a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 7229a1de308cea2d160778fd977825f10a07b49d738Adam Powell 723690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell /** 7243afc18af2cea898753b10e8575dcf20c11356bcaJeff Brown * Gets the default route for playing media content on the system. 7253afc18af2cea898753b10e8575dcf20c11356bcaJeff Brown * <p> 7263afc18af2cea898753b10e8575dcf20c11356bcaJeff Brown * The system always provides a default route. 7273afc18af2cea898753b10e8575dcf20c11356bcaJeff Brown * </p> 7283afc18af2cea898753b10e8575dcf20c11356bcaJeff Brown * 7293afc18af2cea898753b10e8575dcf20c11356bcaJeff Brown * @return The default route, which is guaranteed to never be null. 730690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell */ 7313afc18af2cea898753b10e8575dcf20c11356bcaJeff Brown public RouteInfo getDefaultRoute() { 732705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell return sStatic.mDefaultAudioVideo; 733690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell } 734690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell 735690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell /** 7364599696591f745b3a546197d2ba7e5cfc5562484Adam Powell * @hide for use by framework routing UI 7374599696591f745b3a546197d2ba7e5cfc5562484Adam Powell */ 7383afc18af2cea898753b10e8575dcf20c11356bcaJeff Brown public RouteCategory getSystemCategory() { 7394599696591f745b3a546197d2ba7e5cfc5562484Adam Powell return sStatic.mSystemCategory; 7404599696591f745b3a546197d2ba7e5cfc5562484Adam Powell } 7414599696591f745b3a546197d2ba7e5cfc5562484Adam Powell 7420abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown /** @hide */ 7430abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown public RouteInfo getSelectedRoute() { 7440abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown return getSelectedRoute(ROUTE_TYPE_ANY); 7450abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown } 7460abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown 7474599696591f745b3a546197d2ba7e5cfc5562484Adam Powell /** 7481cf2ca83584a4cf0aa3ded787bd191b9a60e3521Adam Powell * Return the currently selected route for any of the given types 749690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell * 750690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell * @param type route types 751690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell * @return the selected route 752690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell */ 753690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell public RouteInfo getSelectedRoute(int type) { 7541cf2ca83584a4cf0aa3ded787bd191b9a60e3521Adam Powell if (sStatic.mSelectedRoute != null && 7551cf2ca83584a4cf0aa3ded787bd191b9a60e3521Adam Powell (sStatic.mSelectedRoute.mSupportedTypes & type) != 0) { 7561cf2ca83584a4cf0aa3ded787bd191b9a60e3521Adam Powell // If the selected route supports any of the types supplied, it's still considered 7571cf2ca83584a4cf0aa3ded787bd191b9a60e3521Adam Powell // 'selected' for that type. 7581cf2ca83584a4cf0aa3ded787bd191b9a60e3521Adam Powell return sStatic.mSelectedRoute; 7591cf2ca83584a4cf0aa3ded787bd191b9a60e3521Adam Powell } else if (type == ROUTE_TYPE_USER) { 7601cf2ca83584a4cf0aa3ded787bd191b9a60e3521Adam Powell // The caller specifically asked for a user route and the currently selected route 7611cf2ca83584a4cf0aa3ded787bd191b9a60e3521Adam Powell // doesn't qualify. 7621cf2ca83584a4cf0aa3ded787bd191b9a60e3521Adam Powell return null; 7631cf2ca83584a4cf0aa3ded787bd191b9a60e3521Adam Powell } 7641cf2ca83584a4cf0aa3ded787bd191b9a60e3521Adam Powell // If the above didn't match and we're not specifically asking for a user route, 7651cf2ca83584a4cf0aa3ded787bd191b9a60e3521Adam Powell // consider the default selected. 7661cf2ca83584a4cf0aa3ded787bd191b9a60e3521Adam Powell return sStatic.mDefaultAudioVideo; 767690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell } 768690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell 7699a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 7700abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * Returns true if there is a route that matches the specified types. 7710abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * <p> 7720abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * This method returns true if there are any available routes that match the types 7730abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * regardless of whether they are enabled or disabled. If the 7740abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * {@link #AVAILABILITY_FLAG_IGNORE_DEFAULT_ROUTE} flag is specified, then 7750abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * the method will only consider non-default routes. 7760abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * </p> 7770abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * 7780abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * @param types The types to match. 7790abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * @param flags Flags to control the determination of whether a route may be available. 7800abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * May be zero or {@link #AVAILABILITY_FLAG_IGNORE_DEFAULT_ROUTE}. 7810abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * @return True if a matching route may be available. 7820abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * 7830abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * @hide Future API ported from support library. Revisit this later. 7840abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown */ 7850abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown public boolean isRouteAvailable(int types, int flags) { 7860abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown final int count = sStatic.mRoutes.size(); 7870abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown for (int i = 0; i < count; i++) { 7880abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown RouteInfo route = sStatic.mRoutes.get(i); 7890abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown if (route.matchesTypes(types)) { 7900abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown if ((flags & AVAILABILITY_FLAG_IGNORE_DEFAULT_ROUTE) == 0 7910abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown || route != sStatic.mDefaultAudioVideo) { 7920abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown return true; 7930abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown } 7940abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown } 7950abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown } 7960abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown 7970abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown // It doesn't look like we can find a matching route right now. 7980abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown return false; 7990abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown } 8000abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown 8010abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown /** 8029a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Add a callback to listen to events about specific kinds of media routes. 8039a1de308cea2d160778fd977825f10a07b49d738Adam Powell * If the specified callback is already registered, its registration will be updated for any 8049a1de308cea2d160778fd977825f10a07b49d738Adam Powell * additional route types specified. 80566f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * <p> 80666f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * This is a convenience method that has the same effect as calling 80766f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * {@link #addCallback(int, Callback, int)} without flags. 80866f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * </p> 8099a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 8109a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param types Types of routes this callback is interested in 8119a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param cb Callback to add 8129a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 8139a1de308cea2d160778fd977825f10a07b49d738Adam Powell public void addCallback(int types, Callback cb) { 81466f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown addCallback(types, cb, 0); 81566f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown } 81666f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown 81766f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown /** 81866f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * Add a callback to listen to events about specific kinds of media routes. 81966f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * If the specified callback is already registered, its registration will be updated for any 82066f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * additional route types specified. 82166f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * <p> 82266f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * By default, the callback will only be invoked for events that affect routes 82366f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * that match the specified selector. The filtering may be disabled by specifying 82466f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * the {@link #CALLBACK_FLAG_UNFILTERED_EVENTS} flag. 82566f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * </p> 82666f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * 82766f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * @param types Types of routes this callback is interested in 82866f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * @param cb Callback to add 82966f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * @param flags Flags to control the behavior of the callback. 83014507e257af5d71577574e25cbd690c4b54c9272Jeff Brown * May be zero or a combination of {@link #CALLBACK_FLAG_PERFORM_ACTIVE_SCAN} and 83166f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * {@link #CALLBACK_FLAG_UNFILTERED_EVENTS}. 83266f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown */ 83366f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown public void addCallback(int types, Callback cb, int flags) { 83466f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown CallbackInfo info; 83566f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown int index = findCallbackInfo(cb); 83666f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown if (index >= 0) { 83766f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown info = sStatic.mCallbacks.get(index); 83866f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown info.type |= types; 83966f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown info.flags |= flags; 84066f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown } else { 84166f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown info = new CallbackInfo(cb, types, flags, this); 84266f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown sStatic.mCallbacks.add(info); 84366f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown } 84469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown sStatic.updateDiscoveryRequest(); 8459a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 8469a1de308cea2d160778fd977825f10a07b49d738Adam Powell 8479a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 8489a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Remove the specified callback. It will no longer receive events about media routing. 8499a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 8509a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param cb Callback to remove 8519a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 8529a1de308cea2d160778fd977825f10a07b49d738Adam Powell public void removeCallback(Callback cb) { 85366f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown int index = findCallbackInfo(cb); 85466f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown if (index >= 0) { 85569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown sStatic.mCallbacks.remove(index); 85669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown sStatic.updateDiscoveryRequest(); 85766f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown } else { 85866f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown Log.w(TAG, "removeCallback(" + cb + "): callback not registered"); 85966f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown } 86066f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown } 86166f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown 86266f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown private int findCallbackInfo(Callback cb) { 863b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn final int count = sStatic.mCallbacks.size(); 8649a1de308cea2d160778fd977825f10a07b49d738Adam Powell for (int i = 0; i < count; i++) { 86566f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown final CallbackInfo info = sStatic.mCallbacks.get(i); 86666f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown if (info.cb == cb) { 86766f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown return i; 8689a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 8699a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 87066f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown return -1; 8719a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 8729a1de308cea2d160778fd977825f10a07b49d738Adam Powell 873d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell /** 874d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * Select the specified route to use for output of the given media types. 8753afc18af2cea898753b10e8575dcf20c11356bcaJeff Brown * <p class="note"> 8763afc18af2cea898753b10e8575dcf20c11356bcaJeff Brown * As API version 18, this function may be used to select any route. 8773afc18af2cea898753b10e8575dcf20c11356bcaJeff Brown * In prior versions, this function could only be used to select user 8783afc18af2cea898753b10e8575dcf20c11356bcaJeff Brown * routes and would ignore any attempt to select a system route. 8793afc18af2cea898753b10e8575dcf20c11356bcaJeff Brown * </p> 880d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * 881d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param types type flags indicating which types this route should be used for. 882d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * The route must support at least a subset. 883d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param route Route to select 884d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell */ 8859a1de308cea2d160778fd977825f10a07b49d738Adam Powell public void selectRoute(int types, RouteInfo route) { 88669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown selectRouteStatic(types, route, true); 8870d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell } 88869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 8890d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell /** 8900d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * @hide internal use 8910d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell */ 89269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public void selectRouteInt(int types, RouteInfo route, boolean explicit) { 89369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown selectRouteStatic(types, route, explicit); 894b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn } 895b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn 89669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown static void selectRouteStatic(int types, RouteInfo route, boolean explicit) { 897705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell final RouteInfo oldRoute = sStatic.mSelectedRoute; 898705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell if (oldRoute == route) return; 8990abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown if (!route.matchesTypes(types)) { 9000d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell Log.w(TAG, "selectRoute ignored; cannot select route with supported types " + 9010d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell typesToString(route.getSupportedTypes()) + " into route types " + 9020d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell typesToString(types)); 9034ee1f55ce0f4909a7430ab44563a81852f335071Adam Powell return; 9040d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell } 9059a1de308cea2d160778fd977825f10a07b49d738Adam Powell 906dd0a19266d5c837069da1ea188744d54c8d723a8Adam Powell final RouteInfo btRoute = sStatic.mBluetoothA2dpRoute; 907dd0a19266d5c837069da1ea188744d54c8d723a8Adam Powell if (btRoute != null && (types & ROUTE_TYPE_LIVE_AUDIO) != 0 && 908705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell (route == btRoute || route == sStatic.mDefaultAudioVideo)) { 909dd0a19266d5c837069da1ea188744d54c8d723a8Adam Powell try { 910dd0a19266d5c837069da1ea188744d54c8d723a8Adam Powell sStatic.mAudioService.setBluetoothA2dpOn(route == btRoute); 911dd0a19266d5c837069da1ea188744d54c8d723a8Adam Powell } catch (RemoteException e) { 912dd0a19266d5c837069da1ea188744d54c8d723a8Adam Powell Log.e(TAG, "Error changing Bluetooth A2DP state", e); 913dd0a19266d5c837069da1ea188744d54c8d723a8Adam Powell } 914dd0a19266d5c837069da1ea188744d54c8d723a8Adam Powell } 915dd0a19266d5c837069da1ea188744d54c8d723a8Adam Powell 916705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell final WifiDisplay activeDisplay = 917705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell sStatic.mDisplayService.getWifiDisplayStatus().getActiveDisplay(); 918705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell final boolean oldRouteHasAddress = oldRoute != null && oldRoute.mDeviceAddress != null; 919705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell final boolean newRouteHasAddress = route != null && route.mDeviceAddress != null; 920705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell if (activeDisplay != null || oldRouteHasAddress || newRouteHasAddress) { 921705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell if (newRouteHasAddress && !matchesDeviceAddress(activeDisplay, route)) { 922af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown if (sStatic.mCanConfigureWifiDisplays) { 923af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown sStatic.mDisplayService.connectWifiDisplay(route.mDeviceAddress); 924af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown } else { 925af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown Log.e(TAG, "Cannot connect to wifi displays because this process " 926af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown + "is not allowed to do so."); 927af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown } 928705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } else if (activeDisplay != null && !newRouteHasAddress) { 929705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell sStatic.mDisplayService.disconnectWifiDisplay(); 930705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 931705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 932705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 93369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown sStatic.setSelectedRoute(route, explicit); 93469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 935705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell if (oldRoute != null) { 936705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell dispatchRouteUnselected(types & oldRoute.getSupportedTypes(), oldRoute); 93739ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown if (oldRoute.resolveStatusCode()) { 93839ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown dispatchRouteChanged(oldRoute); 93939ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown } 9409a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 9419a1de308cea2d160778fd977825f10a07b49d738Adam Powell if (route != null) { 94239ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown if (route.resolveStatusCode()) { 94339ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown dispatchRouteChanged(route); 94439ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown } 9459a1de308cea2d160778fd977825f10a07b49d738Adam Powell dispatchRouteSelected(types & route.getSupportedTypes(), route); 9469a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 947ce468a35b388ca46578934706b38dbae94941643Jeff Brown 948ce468a35b388ca46578934706b38dbae94941643Jeff Brown // The behavior of active scans may depend on the currently selected route. 949ce468a35b388ca46578934706b38dbae94941643Jeff Brown sStatic.updateDiscoveryRequest(); 9509a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 9519a1de308cea2d160778fd977825f10a07b49d738Adam Powell 95269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown static void selectDefaultRouteStatic() { 95369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // TODO: Be smarter about the route types here; this selects for all valid. 95469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (sStatic.mSelectedRoute != sStatic.mBluetoothA2dpRoute 955f1b2335a36fa6f2b9926f309a7c4ed29a1404ec4Jeff Brown && sStatic.mBluetoothA2dpRoute != null && sStatic.isBluetoothA2dpOn()) { 95669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown selectRouteStatic(ROUTE_TYPE_ANY, sStatic.mBluetoothA2dpRoute, false); 95769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } else { 95869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown selectRouteStatic(ROUTE_TYPE_ANY, sStatic.mDefaultAudioVideo, false); 95969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 96069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 96169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 9629a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 963705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell * Compare the device address of a display and a route. 964705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell * Nulls/no device address will match another null/no address. 965705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell */ 966705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell static boolean matchesDeviceAddress(WifiDisplay display, RouteInfo info) { 967705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell final boolean routeHasAddress = info != null && info.mDeviceAddress != null; 968705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell if (display == null && !routeHasAddress) { 969705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell return true; 970705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 971705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 972705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell if (display != null && routeHasAddress) { 973705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell return display.getDeviceAddress().equals(info.mDeviceAddress); 974705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 975705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell return false; 976705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 977705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 978705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell /** 9799a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Add an app-specified route for media to the MediaRouter. 9809a1de308cea2d160778fd977825f10a07b49d738Adam Powell * App-specified route definitions are created using {@link #createUserRoute(RouteCategory)} 9819a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 9829a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param info Definition of the route to add 9833afc18af2cea898753b10e8575dcf20c11356bcaJeff Brown * @see #createUserRoute(RouteCategory) 9849a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @see #removeUserRoute(UserRouteInfo) 9859a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 9869a1de308cea2d160778fd977825f10a07b49d738Adam Powell public void addUserRoute(UserRouteInfo info) { 9872ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell addRouteStatic(info); 9889a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 9899a1de308cea2d160778fd977825f10a07b49d738Adam Powell 990d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell /** 991d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell * @hide Framework use only 992d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell */ 993d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell public void addRouteInt(RouteInfo info) { 9942ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell addRouteStatic(info); 995d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell } 996d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell 9972ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell static void addRouteStatic(RouteInfo info) { 9989a1de308cea2d160778fd977825f10a07b49d738Adam Powell final RouteCategory cat = info.getCategory(); 999b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn if (!sStatic.mCategories.contains(cat)) { 1000b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn sStatic.mCategories.add(cat); 10019a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 1002d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell if (cat.isGroupable() && !(info instanceof RouteGroup)) { 10039a1de308cea2d160778fd977825f10a07b49d738Adam Powell // Enforce that any added route in a groupable category must be in a group. 10049a1de308cea2d160778fd977825f10a07b49d738Adam Powell final RouteGroup group = new RouteGroup(info.getCategory()); 1005dbbfa702a09f6d2d36dee1b552442d04a4673f89Adam Powell group.mSupportedTypes = info.mSupportedTypes; 1006b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn sStatic.mRoutes.add(group); 1007d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell dispatchRouteAdded(group); 1008b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell group.addRoute(info); 1009d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell 10109a1de308cea2d160778fd977825f10a07b49d738Adam Powell info = group; 1011d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell } else { 1012b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn sStatic.mRoutes.add(info); 1013d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell dispatchRouteAdded(info); 10149a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 10159a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 10169a1de308cea2d160778fd977825f10a07b49d738Adam Powell 10179a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 10189a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Remove an app-specified route for media from the MediaRouter. 10199a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 10209a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param info Definition of the route to remove 10219a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @see #addUserRoute(UserRouteInfo) 10229a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 10239a1de308cea2d160778fd977825f10a07b49d738Adam Powell public void removeUserRoute(UserRouteInfo info) { 102469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown removeRouteStatic(info); 10259a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 10269a1de308cea2d160778fd977825f10a07b49d738Adam Powell 1027690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell /** 1028690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell * Remove all app-specified routes from the MediaRouter. 1029690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell * 1030690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell * @see #removeUserRoute(UserRouteInfo) 1031690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell */ 1032690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell public void clearUserRoutes() { 1033b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn for (int i = 0; i < sStatic.mRoutes.size(); i++) { 1034b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn final RouteInfo info = sStatic.mRoutes.get(i); 1035d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell // TODO Right now, RouteGroups only ever contain user routes. 1036d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell // The code below will need to change if this assumption does. 1037d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell if (info instanceof UserRouteInfo || info instanceof RouteGroup) { 103869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown removeRouteStatic(info); 1039690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell i--; 1040690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell } 1041690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell } 1042690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell } 1043690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell 1044d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell /** 1045d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell * @hide internal use only 1046d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell */ 1047d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell public void removeRouteInt(RouteInfo info) { 104869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown removeRouteStatic(info); 1049d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell } 1050d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell 105169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown static void removeRouteStatic(RouteInfo info) { 1052b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn if (sStatic.mRoutes.remove(info)) { 10539a1de308cea2d160778fd977825f10a07b49d738Adam Powell final RouteCategory removingCat = info.getCategory(); 1054b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn final int count = sStatic.mRoutes.size(); 10559a1de308cea2d160778fd977825f10a07b49d738Adam Powell boolean found = false; 10569a1de308cea2d160778fd977825f10a07b49d738Adam Powell for (int i = 0; i < count; i++) { 1057b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn final RouteCategory cat = sStatic.mRoutes.get(i).getCategory(); 10589a1de308cea2d160778fd977825f10a07b49d738Adam Powell if (removingCat == cat) { 10599a1de308cea2d160778fd977825f10a07b49d738Adam Powell found = true; 10609a1de308cea2d160778fd977825f10a07b49d738Adam Powell break; 10619a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 10629a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 10630abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown if (info.isSelected()) { 1064d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell // Removing the currently selected route? Select the default before we remove it. 106569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown selectDefaultRouteStatic(); 1066d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell } 1067690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell if (!found) { 1068b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn sStatic.mCategories.remove(removingCat); 1069690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell } 1070690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell dispatchRouteRemoved(info); 1071690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell } 1072690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell } 1073690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell 10749a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 10759a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Return the number of {@link MediaRouter.RouteCategory categories} currently 10769a1de308cea2d160778fd977825f10a07b49d738Adam Powell * represented by routes known to this MediaRouter. 10779a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 10789a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @return the number of unique categories represented by this MediaRouter's known routes 10799a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 10809a1de308cea2d160778fd977825f10a07b49d738Adam Powell public int getCategoryCount() { 1081b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn return sStatic.mCategories.size(); 10829a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 10839a1de308cea2d160778fd977825f10a07b49d738Adam Powell 10849a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 10859a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Return the {@link MediaRouter.RouteCategory category} at the given index. 10869a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Valid indices are in the range [0-getCategoryCount). 10879a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 10889a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param index which category to return 10899a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @return the category at index 10909a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 10919a1de308cea2d160778fd977825f10a07b49d738Adam Powell public RouteCategory getCategoryAt(int index) { 1092b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn return sStatic.mCategories.get(index); 10939a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 10949a1de308cea2d160778fd977825f10a07b49d738Adam Powell 10959a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 10969a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Return the number of {@link MediaRouter.RouteInfo routes} currently known 10979a1de308cea2d160778fd977825f10a07b49d738Adam Powell * to this MediaRouter. 10989a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 10999a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @return the number of routes tracked by this router 11009a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 11019a1de308cea2d160778fd977825f10a07b49d738Adam Powell public int getRouteCount() { 1102b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn return sStatic.mRoutes.size(); 11039a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 11049a1de308cea2d160778fd977825f10a07b49d738Adam Powell 11059a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 11069a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Return the route at the specified index. 11079a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 11089a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param index index of the route to return 11099a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @return the route at index 11109a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 11119a1de308cea2d160778fd977825f10a07b49d738Adam Powell public RouteInfo getRouteAt(int index) { 1112b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn return sStatic.mRoutes.get(index); 1113b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn } 1114b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn 1115b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn static int getRouteCountStatic() { 1116b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn return sStatic.mRoutes.size(); 1117b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn } 1118b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn 1119b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn static RouteInfo getRouteAtStatic(int index) { 1120b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn return sStatic.mRoutes.get(index); 11219a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 11229a1de308cea2d160778fd977825f10a07b49d738Adam Powell 11239a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 11249a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Create a new user route that may be modified and registered for use by the application. 11259a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 11269a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param category The category the new route will belong to 11279a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @return A new UserRouteInfo for use by the application 11289a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 11299a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @see #addUserRoute(UserRouteInfo) 11309a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @see #removeUserRoute(UserRouteInfo) 113169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * @see #createRouteCategory(CharSequence, boolean) 11329a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 11339a1de308cea2d160778fd977825f10a07b49d738Adam Powell public UserRouteInfo createUserRoute(RouteCategory category) { 11349a1de308cea2d160778fd977825f10a07b49d738Adam Powell return new UserRouteInfo(category); 11359a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 11369a1de308cea2d160778fd977825f10a07b49d738Adam Powell 11379a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 11389a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Create a new route category. Each route must belong to a category. 11399a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 11409a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param name Name of the new category 11419a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param isGroupable true if routes in this category may be grouped with one another 11429a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @return the new RouteCategory 11439a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 11449a1de308cea2d160778fd977825f10a07b49d738Adam Powell public RouteCategory createRouteCategory(CharSequence name, boolean isGroupable) { 11459a1de308cea2d160778fd977825f10a07b49d738Adam Powell return new RouteCategory(name, ROUTE_TYPE_USER, isGroupable); 11469a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 11475d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik 11480d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell /** 11490d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * Create a new route category. Each route must belong to a category. 11500d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * 11510d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * @param nameResId Resource ID of the name of the new category 11520d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * @param isGroupable true if routes in this category may be grouped with one another 11530d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * @return the new RouteCategory 11540d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell */ 11550d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public RouteCategory createRouteCategory(int nameResId, boolean isGroupable) { 11560d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell return new RouteCategory(nameResId, ROUTE_TYPE_USER, isGroupable); 11570d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell } 11589a1de308cea2d160778fd977825f10a07b49d738Adam Powell 115969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown /** 116069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * Rebinds the media router to handle routes that belong to the specified user. 116169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * Requires the interact across users permission to access the routes of another user. 116269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * <p> 116369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * This method is a complete hack to work around the singleton nature of the 116469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * media router when running inside of singleton processes like QuickSettings. 116569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * This mechanism should be burned to the ground when MediaRouter is redesigned. 116669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * Ideally the current user would be pulled from the Context but we need to break 116769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * down MediaRouter.Static before we can get there. 116869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * </p> 116969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * 117069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * @hide 117169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown */ 117269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public void rebindAsUser(int userId) { 117369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown sStatic.rebindAsUser(userId); 117469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 117569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 1176b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn static void updateRoute(final RouteInfo info) { 11779a1de308cea2d160778fd977825f10a07b49d738Adam Powell dispatchRouteChanged(info); 11789a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 11799a1de308cea2d160778fd977825f10a07b49d738Adam Powell 1180b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn static void dispatchRouteSelected(int type, RouteInfo info) { 118139d5c6172503620ac3761148adac5fd7fa20d02dAdam Powell for (CallbackInfo cbi : sStatic.mCallbacks) { 118266f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown if (cbi.filterRouteEvent(info)) { 1183b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn cbi.cb.onRouteSelected(cbi.router, type, info); 11849a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 11859a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 11869a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 11879a1de308cea2d160778fd977825f10a07b49d738Adam Powell 1188b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn static void dispatchRouteUnselected(int type, RouteInfo info) { 118939d5c6172503620ac3761148adac5fd7fa20d02dAdam Powell for (CallbackInfo cbi : sStatic.mCallbacks) { 119066f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown if (cbi.filterRouteEvent(info)) { 1191b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn cbi.cb.onRouteUnselected(cbi.router, type, info); 11929a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 11939a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 11949a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 11959a1de308cea2d160778fd977825f10a07b49d738Adam Powell 1196b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn static void dispatchRouteChanged(RouteInfo info) { 1197af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown dispatchRouteChanged(info, info.mSupportedTypes); 1198af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown } 1199af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown 1200af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown static void dispatchRouteChanged(RouteInfo info, int oldSupportedTypes) { 1201af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown final int newSupportedTypes = info.mSupportedTypes; 120239d5c6172503620ac3761148adac5fd7fa20d02dAdam Powell for (CallbackInfo cbi : sStatic.mCallbacks) { 1203af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown // Reconstruct some of the history for callbacks that may not have observed 1204af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown // all of the events needed to correctly interpret the current state. 1205af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown // FIXME: This is a strong signal that we should deprecate route type filtering 1206af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown // completely in the future because it can lead to inconsistencies in 1207af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown // applications. 1208af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown final boolean oldVisibility = cbi.filterRouteEvent(oldSupportedTypes); 1209af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown final boolean newVisibility = cbi.filterRouteEvent(newSupportedTypes); 1210af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown if (!oldVisibility && newVisibility) { 1211af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown cbi.cb.onRouteAdded(cbi.router, info); 1212af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown if (info.isSelected()) { 1213af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown cbi.cb.onRouteSelected(cbi.router, newSupportedTypes, info); 1214af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown } 1215af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown } 1216af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown if (oldVisibility || newVisibility) { 1217b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn cbi.cb.onRouteChanged(cbi.router, info); 12189a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 1219af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown if (oldVisibility && !newVisibility) { 1220af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown if (info.isSelected()) { 1221af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown cbi.cb.onRouteUnselected(cbi.router, oldSupportedTypes, info); 1222af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown } 1223af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown cbi.cb.onRouteRemoved(cbi.router, info); 1224af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown } 12259a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 12269a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 12279a1de308cea2d160778fd977825f10a07b49d738Adam Powell 1228b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn static void dispatchRouteAdded(RouteInfo info) { 122939d5c6172503620ac3761148adac5fd7fa20d02dAdam Powell for (CallbackInfo cbi : sStatic.mCallbacks) { 123066f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown if (cbi.filterRouteEvent(info)) { 1231b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn cbi.cb.onRouteAdded(cbi.router, info); 12329a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 12339a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 12349a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 12359a1de308cea2d160778fd977825f10a07b49d738Adam Powell 1236b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn static void dispatchRouteRemoved(RouteInfo info) { 123739d5c6172503620ac3761148adac5fd7fa20d02dAdam Powell for (CallbackInfo cbi : sStatic.mCallbacks) { 123866f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown if (cbi.filterRouteEvent(info)) { 1239b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn cbi.cb.onRouteRemoved(cbi.router, info); 12409a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 12419a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 12429a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 12439a1de308cea2d160778fd977825f10a07b49d738Adam Powell 1244b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn static void dispatchRouteGrouped(RouteInfo info, RouteGroup group, int index) { 124539d5c6172503620ac3761148adac5fd7fa20d02dAdam Powell for (CallbackInfo cbi : sStatic.mCallbacks) { 124666f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown if (cbi.filterRouteEvent(group)) { 1247b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn cbi.cb.onRouteGrouped(cbi.router, info, group, index); 1248d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell } 1249d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell } 1250d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell } 1251d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell 1252b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn static void dispatchRouteUngrouped(RouteInfo info, RouteGroup group) { 125339d5c6172503620ac3761148adac5fd7fa20d02dAdam Powell for (CallbackInfo cbi : sStatic.mCallbacks) { 125466f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown if (cbi.filterRouteEvent(group)) { 1255b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn cbi.cb.onRouteUngrouped(cbi.router, info, group); 12569a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 12579a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 12589a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 12599a1de308cea2d160778fd977825f10a07b49d738Adam Powell 12608e37a85bf3dc39519942698dc90a3951306b934bAdam Powell static void dispatchRouteVolumeChanged(RouteInfo info) { 12618e37a85bf3dc39519942698dc90a3951306b934bAdam Powell for (CallbackInfo cbi : sStatic.mCallbacks) { 126266f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown if (cbi.filterRouteEvent(info)) { 12638e37a85bf3dc39519942698dc90a3951306b934bAdam Powell cbi.cb.onRouteVolumeChanged(cbi.router, info); 12648e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 12658e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 12668e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 12678e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 126892130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown static void dispatchRoutePresentationDisplayChanged(RouteInfo info) { 126992130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown for (CallbackInfo cbi : sStatic.mCallbacks) { 127066f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown if (cbi.filterRouteEvent(info)) { 127192130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown cbi.cb.onRoutePresentationDisplayChanged(cbi.router, info); 127292130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown } 127392130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown } 127492130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown } 127592130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown 12768e37a85bf3dc39519942698dc90a3951306b934bAdam Powell static void systemVolumeChanged(int newValue) { 12778e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final RouteInfo selectedRoute = sStatic.mSelectedRoute; 12788e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (selectedRoute == null) return; 12798e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 12808e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (selectedRoute == sStatic.mBluetoothA2dpRoute || 1281705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell selectedRoute == sStatic.mDefaultAudioVideo) { 12828e37a85bf3dc39519942698dc90a3951306b934bAdam Powell dispatchRouteVolumeChanged(selectedRoute); 12838e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } else if (sStatic.mBluetoothA2dpRoute != null) { 12848e37a85bf3dc39519942698dc90a3951306b934bAdam Powell try { 12858e37a85bf3dc39519942698dc90a3951306b934bAdam Powell dispatchRouteVolumeChanged(sStatic.mAudioService.isBluetoothA2dpOn() ? 1286705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell sStatic.mBluetoothA2dpRoute : sStatic.mDefaultAudioVideo); 12878e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } catch (RemoteException e) { 12888e37a85bf3dc39519942698dc90a3951306b934bAdam Powell Log.e(TAG, "Error checking Bluetooth A2DP state to report volume change", e); 12898e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 12908e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } else { 1291705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell dispatchRouteVolumeChanged(sStatic.mDefaultAudioVideo); 1292705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1293705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1294705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 129575af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown static void updateWifiDisplayStatus(WifiDisplayStatus status) { 129675af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown WifiDisplay[] displays; 1297615e413a90ff5898d8c458ebc9649ca95fa9fd98Adam Powell WifiDisplay activeDisplay; 129875af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown if (status.getFeatureState() == WifiDisplayStatus.FEATURE_STATE_ON) { 129975af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown displays = status.getDisplays(); 130075af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown activeDisplay = status.getActiveDisplay(); 1301af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown 1302af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown // Only the system is able to connect to wifi display routes. 1303af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown // The display manager will enforce this with a permission check but it 1304af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown // still publishes information about all available displays. 1305af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown // Filter the list down to just the active display. 1306af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown if (!sStatic.mCanConfigureWifiDisplays) { 1307af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown if (activeDisplay != null) { 1308af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown displays = new WifiDisplay[] { activeDisplay }; 1309af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown } else { 1310af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown displays = WifiDisplay.EMPTY_ARRAY; 1311af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown } 1312af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown } 1313615e413a90ff5898d8c458ebc9649ca95fa9fd98Adam Powell } else { 131475af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown displays = WifiDisplay.EMPTY_ARRAY; 1315615e413a90ff5898d8c458ebc9649ca95fa9fd98Adam Powell activeDisplay = null; 1316615e413a90ff5898d8c458ebc9649ca95fa9fd98Adam Powell } 1317ce468a35b388ca46578934706b38dbae94941643Jeff Brown String activeDisplayAddress = activeDisplay != null ? 1318ce468a35b388ca46578934706b38dbae94941643Jeff Brown activeDisplay.getDeviceAddress() : null; 1319705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 132075af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown // Add or update routes. 132175af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown for (int i = 0; i < displays.length; i++) { 132275af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown final WifiDisplay d = displays[i]; 132375af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown if (shouldShowWifiDisplay(d, activeDisplay)) { 1324ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang RouteInfo route = findWifiDisplayRoute(d); 1325ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang if (route == null) { 132675af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown route = makeWifiDisplayRoute(d, status); 1327ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang addRouteStatic(route); 1328ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang } else { 1329ce468a35b388ca46578934706b38dbae94941643Jeff Brown String address = d.getDeviceAddress(); 1330ce468a35b388ca46578934706b38dbae94941643Jeff Brown boolean disconnected = !address.equals(activeDisplayAddress) 1331ce468a35b388ca46578934706b38dbae94941643Jeff Brown && address.equals(sStatic.mPreviousActiveWifiDisplayAddress); 1332ce468a35b388ca46578934706b38dbae94941643Jeff Brown updateWifiDisplayRoute(route, d, status, disconnected); 1333ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang } 1334ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang if (d.equals(activeDisplay)) { 133569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown selectRouteStatic(route.getSupportedTypes(), route, false); 1336ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang } 13372ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell } 1338705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 133975af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown 134075af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown // Remove stale routes. 134175af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown for (int i = sStatic.mRoutes.size(); i-- > 0; ) { 134275af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown RouteInfo route = sStatic.mRoutes.get(i); 134375af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown if (route.mDeviceAddress != null) { 134475af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown WifiDisplay d = findWifiDisplay(displays, route.mDeviceAddress); 134575af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown if (d == null || !shouldShowWifiDisplay(d, activeDisplay)) { 134675af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown removeRouteStatic(route); 1347ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang } 1348705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1349705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1350ce468a35b388ca46578934706b38dbae94941643Jeff Brown 1351ce468a35b388ca46578934706b38dbae94941643Jeff Brown // Remember the current active wifi display address so that we can infer disconnections. 1352ce468a35b388ca46578934706b38dbae94941643Jeff Brown // TODO: This hack will go away once all of this is moved into the media router service. 1353ce468a35b388ca46578934706b38dbae94941643Jeff Brown sStatic.mPreviousActiveWifiDisplayAddress = activeDisplayAddress; 135475af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown } 1355705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 135675af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown private static boolean shouldShowWifiDisplay(WifiDisplay d, WifiDisplay activeDisplay) { 135775af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown return d.isRemembered() || d.equals(activeDisplay); 1358705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1359705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 1360ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang static int getWifiDisplayStatusCode(WifiDisplay d, WifiDisplayStatus wfdStatus) { 136169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown int newStatus; 1362ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang if (wfdStatus.getScanState() == WifiDisplayStatus.SCAN_STATE_SCANNING) { 1363ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang newStatus = RouteInfo.STATUS_SCANNING; 1364ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang } else if (d.isAvailable()) { 1365ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang newStatus = d.canConnect() ? 1366ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang RouteInfo.STATUS_AVAILABLE: RouteInfo.STATUS_IN_USE; 1367705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } else { 1368705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell newStatus = RouteInfo.STATUS_NOT_AVAILABLE; 1369705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1370705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 1371ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang if (d.equals(wfdStatus.getActiveDisplay())) { 1372ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang final int activeState = wfdStatus.getActiveDisplayState(); 1373705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell switch (activeState) { 1374705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell case WifiDisplayStatus.DISPLAY_STATE_CONNECTED: 137569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown newStatus = RouteInfo.STATUS_CONNECTED; 1376705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell break; 1377705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell case WifiDisplayStatus.DISPLAY_STATE_CONNECTING: 1378705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell newStatus = RouteInfo.STATUS_CONNECTING; 1379705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell break; 1380705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell case WifiDisplayStatus.DISPLAY_STATE_NOT_CONNECTED: 1381705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell Log.e(TAG, "Active display is not connected!"); 1382705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell break; 1383705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1384705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1385705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 1386ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang return newStatus; 1387ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang } 1388ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang 1389ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang static boolean isWifiDisplayEnabled(WifiDisplay d, WifiDisplayStatus wfdStatus) { 1390ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang return d.isAvailable() && (d.canConnect() || d.equals(wfdStatus.getActiveDisplay())); 1391ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang } 1392ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang 1393ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang static RouteInfo makeWifiDisplayRoute(WifiDisplay display, WifiDisplayStatus wfdStatus) { 1394ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang final RouteInfo newRoute = new RouteInfo(sStatic.mSystemCategory); 1395ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang newRoute.mDeviceAddress = display.getDeviceAddress(); 139669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown newRoute.mSupportedTypes = ROUTE_TYPE_LIVE_AUDIO | ROUTE_TYPE_LIVE_VIDEO 139769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown | ROUTE_TYPE_REMOTE_DISPLAY; 1398ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang newRoute.mVolumeHandling = RouteInfo.PLAYBACK_VOLUME_FIXED; 1399ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang newRoute.mPlaybackType = RouteInfo.PLAYBACK_TYPE_REMOTE; 1400ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang 140139ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown newRoute.setRealStatusCode(getWifiDisplayStatusCode(display, wfdStatus)); 1402ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang newRoute.mEnabled = isWifiDisplayEnabled(display, wfdStatus); 1403ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang newRoute.mName = display.getFriendlyDisplayName(); 1404ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang newRoute.mDescription = sStatic.mResources.getText( 1405ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang com.android.internal.R.string.wireless_display_route_description); 14065830b0b33618940d65197cec99d697b21908fec8Chong Zhang newRoute.updatePresentationDisplay(); 1407ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang return newRoute; 1408ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang } 1409ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang 1410ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang private static void updateWifiDisplayRoute( 1411ce468a35b388ca46578934706b38dbae94941643Jeff Brown RouteInfo route, WifiDisplay display, WifiDisplayStatus wfdStatus, 1412ce468a35b388ca46578934706b38dbae94941643Jeff Brown boolean disconnected) { 1413ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang boolean changed = false; 14142444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown final String newName = display.getFriendlyDisplayName(); 14152444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown if (!route.getName().equals(newName)) { 1416705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell route.mName = newName; 1417705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell changed = true; 1418705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1419705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 1420ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang boolean enabled = isWifiDisplayEnabled(display, wfdStatus); 1421ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang changed |= route.mEnabled != enabled; 1422ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang route.mEnabled = enabled; 1423705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 142439ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown changed |= route.setRealStatusCode(getWifiDisplayStatusCode(display, wfdStatus)); 1425705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 1426705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell if (changed) { 1427705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell dispatchRouteChanged(route); 1428705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1429705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 1430ce468a35b388ca46578934706b38dbae94941643Jeff Brown if ((!enabled || disconnected) && route.isSelected()) { 1431705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell // Oops, no longer available. Reselect the default. 143269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown selectDefaultRouteStatic(); 1433705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1434705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1435705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 143675af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown private static WifiDisplay findWifiDisplay(WifiDisplay[] displays, String deviceAddress) { 1437705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell for (int i = 0; i < displays.length; i++) { 143875af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown final WifiDisplay d = displays[i]; 143975af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown if (d.getDeviceAddress().equals(deviceAddress)) { 144075af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown return d; 1441705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1442705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1443705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell return null; 1444705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1445705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 1446705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell private static RouteInfo findWifiDisplayRoute(WifiDisplay d) { 1447705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell final int count = sStatic.mRoutes.size(); 1448705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell for (int i = 0; i < count; i++) { 1449705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell final RouteInfo info = sStatic.mRoutes.get(i); 1450705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell if (d.getDeviceAddress().equals(info.mDeviceAddress)) { 1451705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell return info; 1452705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1453705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1454705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell return null; 14558e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 14568e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 14579a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 14589a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Information about a media route. 14599a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 1460b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn public static class RouteInfo { 14619a1de308cea2d160778fd977825f10a07b49d738Adam Powell CharSequence mName; 14620d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell int mNameResId; 146356d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown CharSequence mDescription; 14649a1de308cea2d160778fd977825f10a07b49d738Adam Powell private CharSequence mStatus; 14659a1de308cea2d160778fd977825f10a07b49d738Adam Powell int mSupportedTypes; 14669a1de308cea2d160778fd977825f10a07b49d738Adam Powell RouteGroup mGroup; 14679a1de308cea2d160778fd977825f10a07b49d738Adam Powell final RouteCategory mCategory; 1468ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell Drawable mIcon; 14691357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi // playback information 14701357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi int mPlaybackType = PLAYBACK_TYPE_LOCAL; 14711357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi int mVolumeMax = RemoteControlClient.DEFAULT_PLAYBACK_VOLUME; 14721357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi int mVolume = RemoteControlClient.DEFAULT_PLAYBACK_VOLUME; 14731357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi int mVolumeHandling = RemoteControlClient.DEFAULT_PLAYBACK_VOLUME_HANDLING; 14741357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi int mPlaybackStream = AudioManager.STREAM_MUSIC; 14751357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi VolumeCallbackInfo mVcb; 147692130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown Display mPresentationDisplay; 14775830b0b33618940d65197cec99d697b21908fec8Chong Zhang int mPresentationDisplayId = -1; 14789a1de308cea2d160778fd977825f10a07b49d738Adam Powell 1479705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell String mDeviceAddress; 1480705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell boolean mEnabled = true; 1481705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 148269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // An id by which the route is known to the media router service. 148369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Null if this route only exists as an artifact within this process. 148469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown String mGlobalRouteId; 148569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 1486705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell // A predetermined connection status that can override mStatus 148739ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown private int mRealStatusCode; 148839ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown private int mResolvedStatusCode; 1489705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 14902ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell /** @hide */ public static final int STATUS_NONE = 0; 14912ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell /** @hide */ public static final int STATUS_SCANNING = 1; 14922ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell /** @hide */ public static final int STATUS_CONNECTING = 2; 14932ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell /** @hide */ public static final int STATUS_AVAILABLE = 3; 14942ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell /** @hide */ public static final int STATUS_NOT_AVAILABLE = 4; 1495ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang /** @hide */ public static final int STATUS_IN_USE = 5; 149669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown /** @hide */ public static final int STATUS_CONNECTED = 6; 1497705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 1498b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell private Object mTag; 1499b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell 15001357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 15011357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * The default playback type, "local", indicating the presentation of the media is happening 15021357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * on the same device (e.g. a phone, a tablet) as where it is controlled from. 150369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * @see #getPlaybackType() 15041357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 15051357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public final static int PLAYBACK_TYPE_LOCAL = 0; 15061357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 15071357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * A playback type indicating the presentation of the media is happening on 15081357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * a different device (i.e. the remote device) than where it is controlled from. 150969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * @see #getPlaybackType() 15101357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 15111357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public final static int PLAYBACK_TYPE_REMOTE = 1; 15121357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 15131357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * Playback information indicating the playback volume is fixed, i.e. it cannot be 15141357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * controlled from this object. An example of fixed playback volume is a remote player, 15151357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * playing over HDMI where the user prefers to control the volume on the HDMI sink, rather 15161357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * than attenuate at the source. 151769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * @see #getVolumeHandling() 15181357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 15191357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public final static int PLAYBACK_VOLUME_FIXED = 0; 15201357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 15211357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * Playback information indicating the playback volume is variable and can be controlled 15221357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * from this object. 152369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * @see #getVolumeHandling() 15241357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 15251357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public final static int PLAYBACK_VOLUME_VARIABLE = 1; 15261357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 15279a1de308cea2d160778fd977825f10a07b49d738Adam Powell RouteInfo(RouteCategory category) { 15289a1de308cea2d160778fd977825f10a07b49d738Adam Powell mCategory = category; 15299a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 15309a1de308cea2d160778fd977825f10a07b49d738Adam Powell 15319a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 153256d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * Gets the user-visible name of the route. 153356d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * <p> 153456d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * The route name identifies the destination represented by the route. 153556d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * It may be a user-supplied name, an alias, or device serial number. 153656d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * </p> 153756d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * 153856d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * @return The user-visible name of a media route. This is the string presented 15399a1de308cea2d160778fd977825f10a07b49d738Adam Powell * to users who may select this as the active route. 15409a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 15419a1de308cea2d160778fd977825f10a07b49d738Adam Powell public CharSequence getName() { 15420d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell return getName(sStatic.mResources); 15430d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell } 154456d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown 15450d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell /** 154656d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * Return the properly localized/resource user-visible name of this route. 154756d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * <p> 154856d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * The route name identifies the destination represented by the route. 154956d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * It may be a user-supplied name, an alias, or device serial number. 155056d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * </p> 155156d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * 15520d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * @param context Context used to resolve the correct configuration to load 155356d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * @return The user-visible name of a media route. This is the string presented 15540d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * to users who may select this as the active route. 15550d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell */ 15560d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public CharSequence getName(Context context) { 15570d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell return getName(context.getResources()); 15580d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell } 155956d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown 15600d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell CharSequence getName(Resources res) { 15610d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell if (mNameResId != 0) { 15620d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell return mName = res.getText(mNameResId); 15630d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell } 15649a1de308cea2d160778fd977825f10a07b49d738Adam Powell return mName; 15659a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 15669a1de308cea2d160778fd977825f10a07b49d738Adam Powell 15679a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 156856d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * Gets the user-visible description of the route. 156956d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * <p> 157056d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * The route description describes the kind of destination represented by the route. 157156d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * It may be a user-supplied string, a model number or brand of device. 157256d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * </p> 157356d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * 157456d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * @return The description of the route, or null if none. 157556d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown */ 157656d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown public CharSequence getDescription() { 157756d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown return mDescription; 157856d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown } 157956d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown 158056d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown /** 158156d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * @return The user-visible status for a media route. This may include a description 15829a1de308cea2d160778fd977825f10a07b49d738Adam Powell * of the currently playing media, if available. 15839a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 15849a1de308cea2d160778fd977825f10a07b49d738Adam Powell public CharSequence getStatus() { 15859a1de308cea2d160778fd977825f10a07b49d738Adam Powell return mStatus; 15869a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 15879a1de308cea2d160778fd977825f10a07b49d738Adam Powell 15889a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 1589705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell * Set this route's status by predetermined status code. If the caller 1590705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell * should dispatch a route changed event this call will return true; 1591705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell */ 159239ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown boolean setRealStatusCode(int statusCode) { 159339ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown if (mRealStatusCode != statusCode) { 159439ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown mRealStatusCode = statusCode; 159539ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown return resolveStatusCode(); 159639ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown } 159739ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown return false; 159839ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown } 159939ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown 160039ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown /** 160139ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown * Resolves the status code whenever the real status code or selection state 160239ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown * changes. 160339ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown */ 160439ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown boolean resolveStatusCode() { 160539ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown int statusCode = mRealStatusCode; 160639ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown if (isSelected()) { 1607705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell switch (statusCode) { 160839ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown // If the route is selected and its status appears to be between states 160939ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown // then report it as connecting even though it has not yet had a chance 161039ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown // to officially move into the CONNECTING state. Note that routes in 161139ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown // the NONE state are assumed to not require an explicit connection 161239ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown // lifecycle whereas those that are AVAILABLE are assumed to have 161339ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown // to eventually proceed to CONNECTED. 1614705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell case STATUS_AVAILABLE: 161539ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown case STATUS_SCANNING: 161639ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown statusCode = STATUS_CONNECTING; 161769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown break; 1618705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1619705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 162039ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown if (mResolvedStatusCode == statusCode) { 162139ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown return false; 162239ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown } 162339ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown 162439ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown mResolvedStatusCode = statusCode; 162539ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown int resId; 162639ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown switch (statusCode) { 162739ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown case STATUS_SCANNING: 162839ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown resId = com.android.internal.R.string.media_route_status_scanning; 162939ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown break; 163039ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown case STATUS_CONNECTING: 163139ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown resId = com.android.internal.R.string.media_route_status_connecting; 163239ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown break; 163339ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown case STATUS_AVAILABLE: 163439ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown resId = com.android.internal.R.string.media_route_status_available; 163539ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown break; 163639ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown case STATUS_NOT_AVAILABLE: 163739ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown resId = com.android.internal.R.string.media_route_status_not_available; 163839ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown break; 163939ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown case STATUS_IN_USE: 164039ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown resId = com.android.internal.R.string.media_route_status_in_use; 164139ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown break; 164239ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown case STATUS_CONNECTED: 164339ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown case STATUS_NONE: 164439ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown default: 164539ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown resId = 0; 164639ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown break; 164739ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown } 164839ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown mStatus = resId != 0 ? sStatic.mResources.getText(resId) : null; 164939ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown return true; 1650705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1651705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 1652705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell /** 16532ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell * @hide 16542ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell */ 16552ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell public int getStatusCode() { 165639ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown return mResolvedStatusCode; 16572ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell } 16582ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell 16592ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell /** 16609a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @return A media type flag set describing which types this route supports. 16619a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 16629a1de308cea2d160778fd977825f10a07b49d738Adam Powell public int getSupportedTypes() { 16639a1de308cea2d160778fd977825f10a07b49d738Adam Powell return mSupportedTypes; 16649a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 16659a1de308cea2d160778fd977825f10a07b49d738Adam Powell 16660abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown /** @hide */ 16670abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown public boolean matchesTypes(int types) { 16680abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown return (mSupportedTypes & types) != 0; 16690abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown } 16700abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown 16719a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 16729a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @return The group that this route belongs to. 16739a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 16749a1de308cea2d160778fd977825f10a07b49d738Adam Powell public RouteGroup getGroup() { 16759a1de308cea2d160778fd977825f10a07b49d738Adam Powell return mGroup; 16769a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 16779a1de308cea2d160778fd977825f10a07b49d738Adam Powell 16789a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 16799a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @return the category this route belongs to. 16809a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 16819a1de308cea2d160778fd977825f10a07b49d738Adam Powell public RouteCategory getCategory() { 16829a1de308cea2d160778fd977825f10a07b49d738Adam Powell return mCategory; 16839a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 16849a1de308cea2d160778fd977825f10a07b49d738Adam Powell 1685ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell /** 1686ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * Get the icon representing this route. 1687ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * This icon will be used in picker UIs if available. 1688ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * 1689ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * @return the icon representing this route or null if no icon is available 1690ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell */ 1691ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell public Drawable getIconDrawable() { 1692ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell return mIcon; 1693ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell } 1694ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell 1695b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell /** 1696b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell * Set an application-specific tag object for this route. 1697b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell * The application may use this to store arbitrary data associated with the 1698b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell * route for internal tracking. 1699b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell * 1700b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell * <p>Note that the lifespan of a route may be well past the lifespan of 1701b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell * an Activity or other Context; take care that objects you store here 1702b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell * will not keep more data in memory alive than you intend.</p> 1703b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell * 1704b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell * @param tag Arbitrary, app-specific data for this route to hold for later use 1705b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell */ 1706b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell public void setTag(Object tag) { 1707b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell mTag = tag; 1708130b4572d1f3df702e5b296a655d15a41f6d4c66Adam Powell routeUpdated(); 1709b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell } 1710b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell 1711b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell /** 1712b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell * @return The tag object previously set by the application 1713b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell * @see #setTag(Object) 1714b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell */ 1715b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell public Object getTag() { 1716b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell return mTag; 1717b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell } 1718b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell 17191357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 17201357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @return the type of playback associated with this route 17211357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @see UserRouteInfo#setPlaybackType(int) 17221357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 17231357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public int getPlaybackType() { 17241357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi return mPlaybackType; 17251357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 17261357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 17271357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 17281357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @return the stream over which the playback associated with this route is performed 17291357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @see UserRouteInfo#setPlaybackStream(int) 17301357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 17311357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public int getPlaybackStream() { 17321357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi return mPlaybackStream; 17331357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 17341357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 17351357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 17368e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * Return the current volume for this route. Depending on the route, this may only 17378e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * be valid if the route is currently selected. 17388e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * 17391357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @return the volume at which the playback associated with this route is performed 17401357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @see UserRouteInfo#setVolume(int) 17411357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 17421357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public int getVolume() { 17431357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi if (mPlaybackType == PLAYBACK_TYPE_LOCAL) { 17441357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi int vol = 0; 17451357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi try { 17461357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi vol = sStatic.mAudioService.getStreamVolume(mPlaybackStream); 17471357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } catch (RemoteException e) { 17481357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi Log.e(TAG, "Error getting local stream volume", e); 17491357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 17501357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi return vol; 17511357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } else { 17521357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi return mVolume; 17531357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 17541357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 17551357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 17561357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 17578e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * Request a volume change for this route. 17588e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * @param volume value between 0 and getVolumeMax 17598e37a85bf3dc39519942698dc90a3951306b934bAdam Powell */ 17608e37a85bf3dc39519942698dc90a3951306b934bAdam Powell public void requestSetVolume(int volume) { 17618e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (mPlaybackType == PLAYBACK_TYPE_LOCAL) { 17628e37a85bf3dc39519942698dc90a3951306b934bAdam Powell try { 1763ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn sStatic.mAudioService.setStreamVolume(mPlaybackStream, volume, 0, 1764ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn ActivityThread.currentPackageName()); 17658e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } catch (RemoteException e) { 17668e37a85bf3dc39519942698dc90a3951306b934bAdam Powell Log.e(TAG, "Error setting local stream volume", e); 17678e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 17688e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } else { 176969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown sStatic.requestSetVolume(this, volume); 17708e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 17718e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 17728e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 17738e37a85bf3dc39519942698dc90a3951306b934bAdam Powell /** 17748e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * Request an incremental volume update for this route. 17758e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * @param direction Delta to apply to the current volume 17768e37a85bf3dc39519942698dc90a3951306b934bAdam Powell */ 17778e37a85bf3dc39519942698dc90a3951306b934bAdam Powell public void requestUpdateVolume(int direction) { 17788e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (mPlaybackType == PLAYBACK_TYPE_LOCAL) { 17798e37a85bf3dc39519942698dc90a3951306b934bAdam Powell try { 17808e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final int volume = 17818e37a85bf3dc39519942698dc90a3951306b934bAdam Powell Math.max(0, Math.min(getVolume() + direction, getVolumeMax())); 1782ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn sStatic.mAudioService.setStreamVolume(mPlaybackStream, volume, 0, 1783ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn ActivityThread.currentPackageName()); 17848e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } catch (RemoteException e) { 17858e37a85bf3dc39519942698dc90a3951306b934bAdam Powell Log.e(TAG, "Error setting local stream volume", e); 17868e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 17878e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } else { 178869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown sStatic.requestUpdateVolume(this, direction); 17898e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 17908e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 17918e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 17928e37a85bf3dc39519942698dc90a3951306b934bAdam Powell /** 17931357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @return the maximum volume at which the playback associated with this route is performed 17941357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @see UserRouteInfo#setVolumeMax(int) 17951357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 17961357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public int getVolumeMax() { 17971357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi if (mPlaybackType == PLAYBACK_TYPE_LOCAL) { 17981357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi int volMax = 0; 17991357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi try { 18001357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi volMax = sStatic.mAudioService.getStreamMaxVolume(mPlaybackStream); 18011357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } catch (RemoteException e) { 18021357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi Log.e(TAG, "Error getting local stream volume", e); 18031357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 18041357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi return volMax; 18051357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } else { 18061357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi return mVolumeMax; 18071357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 18081357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 18091357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 18101357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 18111357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @return how volume is handling on the route 18121357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @see UserRouteInfo#setVolumeHandling(int) 18131357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 18141357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public int getVolumeHandling() { 18151357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi return mVolumeHandling; 18161357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 18171357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 1818705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell /** 181992130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * Gets the {@link Display} that should be used by the application to show 182092130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * a {@link android.app.Presentation} on an external display when this route is selected. 182192130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * Depending on the route, this may only be valid if the route is currently 182292130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * selected. 182392130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * <p> 182492130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * The preferred presentation display may change independently of the route 182592130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * being selected or unselected. For example, the presentation display 182692130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * of the default system route may change when an external HDMI display is connected 182792130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * or disconnected even though the route itself has not changed. 182892130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * </p><p> 182992130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * This method may return null if there is no external display associated with 183092130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * the route or if the display is not ready to show UI yet. 183192130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * </p><p> 183292130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * The application should listen for changes to the presentation display 183392130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * using the {@link Callback#onRoutePresentationDisplayChanged} callback and 183492130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * show or dismiss its {@link android.app.Presentation} accordingly when the display 183592130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * becomes available or is removed. 183692130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * </p><p> 183792130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * This method only makes sense for {@link #ROUTE_TYPE_LIVE_VIDEO live video} routes. 183892130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * </p> 183992130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * 184092130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * @return The preferred presentation display to use when this route is 184192130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * selected or null if none. 184292130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * 184392130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * @see #ROUTE_TYPE_LIVE_VIDEO 184492130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * @see android.app.Presentation 184592130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown */ 184692130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown public Display getPresentationDisplay() { 184792130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown return mPresentationDisplay; 184892130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown } 184992130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown 18505830b0b33618940d65197cec99d697b21908fec8Chong Zhang boolean updatePresentationDisplay() { 18515830b0b33618940d65197cec99d697b21908fec8Chong Zhang Display display = choosePresentationDisplay(); 18525830b0b33618940d65197cec99d697b21908fec8Chong Zhang if (mPresentationDisplay != display) { 18535830b0b33618940d65197cec99d697b21908fec8Chong Zhang mPresentationDisplay = display; 18545830b0b33618940d65197cec99d697b21908fec8Chong Zhang return true; 18555830b0b33618940d65197cec99d697b21908fec8Chong Zhang } 18565830b0b33618940d65197cec99d697b21908fec8Chong Zhang return false; 18575830b0b33618940d65197cec99d697b21908fec8Chong Zhang } 18585830b0b33618940d65197cec99d697b21908fec8Chong Zhang 18595830b0b33618940d65197cec99d697b21908fec8Chong Zhang private Display choosePresentationDisplay() { 18605830b0b33618940d65197cec99d697b21908fec8Chong Zhang if ((mSupportedTypes & ROUTE_TYPE_LIVE_VIDEO) != 0) { 18615830b0b33618940d65197cec99d697b21908fec8Chong Zhang Display[] displays = sStatic.getAllPresentationDisplays(); 18625830b0b33618940d65197cec99d697b21908fec8Chong Zhang 18635830b0b33618940d65197cec99d697b21908fec8Chong Zhang // Ensure that the specified display is valid for presentations. 18645830b0b33618940d65197cec99d697b21908fec8Chong Zhang // This check will normally disallow the default display unless it was 18655830b0b33618940d65197cec99d697b21908fec8Chong Zhang // configured as a presentation display for some reason. 18665830b0b33618940d65197cec99d697b21908fec8Chong Zhang if (mPresentationDisplayId >= 0) { 18675830b0b33618940d65197cec99d697b21908fec8Chong Zhang for (Display display : displays) { 18685830b0b33618940d65197cec99d697b21908fec8Chong Zhang if (display.getDisplayId() == mPresentationDisplayId) { 18695830b0b33618940d65197cec99d697b21908fec8Chong Zhang return display; 18705830b0b33618940d65197cec99d697b21908fec8Chong Zhang } 18715830b0b33618940d65197cec99d697b21908fec8Chong Zhang } 18725830b0b33618940d65197cec99d697b21908fec8Chong Zhang return null; 18735830b0b33618940d65197cec99d697b21908fec8Chong Zhang } 18745830b0b33618940d65197cec99d697b21908fec8Chong Zhang 18755830b0b33618940d65197cec99d697b21908fec8Chong Zhang // Find the indicated Wifi display by its address. 18765830b0b33618940d65197cec99d697b21908fec8Chong Zhang if (mDeviceAddress != null) { 18775830b0b33618940d65197cec99d697b21908fec8Chong Zhang for (Display display : displays) { 18785830b0b33618940d65197cec99d697b21908fec8Chong Zhang if (display.getType() == Display.TYPE_WIFI 18795830b0b33618940d65197cec99d697b21908fec8Chong Zhang && mDeviceAddress.equals(display.getAddress())) { 18805830b0b33618940d65197cec99d697b21908fec8Chong Zhang return display; 18815830b0b33618940d65197cec99d697b21908fec8Chong Zhang } 18825830b0b33618940d65197cec99d697b21908fec8Chong Zhang } 18835830b0b33618940d65197cec99d697b21908fec8Chong Zhang return null; 18845830b0b33618940d65197cec99d697b21908fec8Chong Zhang } 18855830b0b33618940d65197cec99d697b21908fec8Chong Zhang 18865830b0b33618940d65197cec99d697b21908fec8Chong Zhang // For the default route, choose the first presentation display from the list. 18875830b0b33618940d65197cec99d697b21908fec8Chong Zhang if (this == sStatic.mDefaultAudioVideo && displays.length > 0) { 18885830b0b33618940d65197cec99d697b21908fec8Chong Zhang return displays[0]; 18895830b0b33618940d65197cec99d697b21908fec8Chong Zhang } 18905830b0b33618940d65197cec99d697b21908fec8Chong Zhang } 18915830b0b33618940d65197cec99d697b21908fec8Chong Zhang return null; 18925830b0b33618940d65197cec99d697b21908fec8Chong Zhang } 18935830b0b33618940d65197cec99d697b21908fec8Chong Zhang 189475af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown /** @hide */ 189575af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown public String getDeviceAddress() { 189675af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown return mDeviceAddress; 189775af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown } 189875af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown 189992130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown /** 1900a27b8fb4296c1271ddf5916843ddffda6764e65fJeff Brown * Returns true if this route is enabled and may be selected. 1901a27b8fb4296c1271ddf5916843ddffda6764e65fJeff Brown * 1902a27b8fb4296c1271ddf5916843ddffda6764e65fJeff Brown * @return True if this route is enabled. 1903705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell */ 1904705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell public boolean isEnabled() { 1905705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell return mEnabled; 1906705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1907705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 1908a27b8fb4296c1271ddf5916843ddffda6764e65fJeff Brown /** 1909a27b8fb4296c1271ddf5916843ddffda6764e65fJeff Brown * Returns true if the route is in the process of connecting and is not 1910a27b8fb4296c1271ddf5916843ddffda6764e65fJeff Brown * yet ready for use. 1911a27b8fb4296c1271ddf5916843ddffda6764e65fJeff Brown * 1912a27b8fb4296c1271ddf5916843ddffda6764e65fJeff Brown * @return True if this route is in the process of connecting. 1913a27b8fb4296c1271ddf5916843ddffda6764e65fJeff Brown */ 1914a27b8fb4296c1271ddf5916843ddffda6764e65fJeff Brown public boolean isConnecting() { 191539ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown return mResolvedStatusCode == STATUS_CONNECTING; 19160abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown } 19170abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown 19180abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown /** @hide */ 19190abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown public boolean isSelected() { 19200abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown return this == sStatic.mSelectedRoute; 19210abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown } 19220abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown 19230abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown /** @hide */ 19240abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown public boolean isDefault() { 19250abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown return this == sStatic.mDefaultAudioVideo; 19260abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown } 19270abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown 19280abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown /** @hide */ 19290abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown public void select() { 19300abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown selectRouteStatic(mSupportedTypes, this, true); 1931a27b8fb4296c1271ddf5916843ddffda6764e65fJeff Brown } 1932a27b8fb4296c1271ddf5916843ddffda6764e65fJeff Brown 19339a1de308cea2d160778fd977825f10a07b49d738Adam Powell void setStatusInt(CharSequence status) { 19349a1de308cea2d160778fd977825f10a07b49d738Adam Powell if (!status.equals(mStatus)) { 19359a1de308cea2d160778fd977825f10a07b49d738Adam Powell mStatus = status; 19369a1de308cea2d160778fd977825f10a07b49d738Adam Powell if (mGroup != null) { 19379a1de308cea2d160778fd977825f10a07b49d738Adam Powell mGroup.memberStatusChanged(this, status); 19389a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 19399a1de308cea2d160778fd977825f10a07b49d738Adam Powell routeUpdated(); 19409a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 19419a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 19429a1de308cea2d160778fd977825f10a07b49d738Adam Powell 19431357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi final IRemoteVolumeObserver.Stub mRemoteVolObserver = new IRemoteVolumeObserver.Stub() { 194469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown @Override 19451357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public void dispatchRemoteVolumeUpdate(final int direction, final int value) { 19461357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi sStatic.mHandler.post(new Runnable() { 19471357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi @Override 19481357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public void run() { 19491357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi if (mVcb != null) { 19501357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi if (direction != 0) { 19511357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi mVcb.vcb.onVolumeUpdateRequest(mVcb.route, direction); 19521357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } else { 19531357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi mVcb.vcb.onVolumeSetRequest(mVcb.route, value); 19541357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 19551357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 19561357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 19571357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi }); 19581357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 19591357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi }; 19601357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 19619a1de308cea2d160778fd977825f10a07b49d738Adam Powell void routeUpdated() { 19629a1de308cea2d160778fd977825f10a07b49d738Adam Powell updateRoute(this); 19639a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 19649a1de308cea2d160778fd977825f10a07b49d738Adam Powell 19659a1de308cea2d160778fd977825f10a07b49d738Adam Powell @Override 19669a1de308cea2d160778fd977825f10a07b49d738Adam Powell public String toString() { 1967d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell String supportedTypes = typesToString(getSupportedTypes()); 196892130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown return getClass().getSimpleName() + "{ name=" + getName() + 196956d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown ", description=" + getDescription() + 197092130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown ", status=" + getStatus() + 197192130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown ", category=" + getCategory() + 197292130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown ", supportedTypes=" + supportedTypes + 197369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown ", presentationDisplay=" + mPresentationDisplay + " }"; 19749a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 19759a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 19769a1de308cea2d160778fd977825f10a07b49d738Adam Powell 19779a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 19789a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Information about a route that the application may define and modify. 19798e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * A user route defaults to {@link RouteInfo#PLAYBACK_TYPE_REMOTE} and 19808e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * {@link RouteInfo#PLAYBACK_VOLUME_FIXED}. 19819a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 19829a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @see MediaRouter.RouteInfo 19839a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 1984b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn public static class UserRouteInfo extends RouteInfo { 1985ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell RemoteControlClient mRcc; 19865d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik SessionVolumeProvider mSvp; 19879a1de308cea2d160778fd977825f10a07b49d738Adam Powell 19889a1de308cea2d160778fd977825f10a07b49d738Adam Powell UserRouteInfo(RouteCategory category) { 19899a1de308cea2d160778fd977825f10a07b49d738Adam Powell super(category); 19909a1de308cea2d160778fd977825f10a07b49d738Adam Powell mSupportedTypes = ROUTE_TYPE_USER; 19918e37a85bf3dc39519942698dc90a3951306b934bAdam Powell mPlaybackType = PLAYBACK_TYPE_REMOTE; 19928e37a85bf3dc39519942698dc90a3951306b934bAdam Powell mVolumeHandling = PLAYBACK_VOLUME_FIXED; 19939a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 19949a1de308cea2d160778fd977825f10a07b49d738Adam Powell 19959a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 19969a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Set the user-visible name of this route. 19979a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param name Name to display to the user to describe this route 19989a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 19999a1de308cea2d160778fd977825f10a07b49d738Adam Powell public void setName(CharSequence name) { 20009a1de308cea2d160778fd977825f10a07b49d738Adam Powell mName = name; 20019a1de308cea2d160778fd977825f10a07b49d738Adam Powell routeUpdated(); 20029a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 20035d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik 20040d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell /** 20050d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * Set the user-visible name of this route. 200656d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * <p> 200756d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * The route name identifies the destination represented by the route. 200856d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * It may be a user-supplied name, an alias, or device serial number. 200956d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * </p> 201056d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * 20110d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * @param resId Resource ID of the name to display to the user to describe this route 20120d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell */ 20130d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public void setName(int resId) { 20140d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell mNameResId = resId; 20150d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell mName = null; 20160d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell routeUpdated(); 20170d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell } 20189a1de308cea2d160778fd977825f10a07b49d738Adam Powell 20199a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 202056d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * Set the user-visible description of this route. 202156d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * <p> 202256d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * The route description describes the kind of destination represented by the route. 202356d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * It may be a user-supplied string, a model number or brand of device. 202456d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * </p> 202556d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * 202656d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * @param description The description of the route, or null if none. 202756d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown */ 202856d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown public void setDescription(CharSequence description) { 202956d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown mDescription = description; 203056d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown routeUpdated(); 203156d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown } 203256d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown 203356d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown /** 20349a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Set the current user-visible status for this route. 20359a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param status Status to display to the user to describe what the endpoint 20369a1de308cea2d160778fd977825f10a07b49d738Adam Powell * of this route is currently doing 20379a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 20389a1de308cea2d160778fd977825f10a07b49d738Adam Powell public void setStatus(CharSequence status) { 20399a1de308cea2d160778fd977825f10a07b49d738Adam Powell setStatusInt(status); 20409a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 2041ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell 2042ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell /** 2043ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * Set the RemoteControlClient responsible for reporting playback info for this 2044ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * user route. 2045ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * 2046ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * <p>If this route manages remote playback, the data exposed by this 2047ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * RemoteControlClient will be used to reflect and update information 2048ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * such as route volume info in related UIs.</p> 2049ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * 20501357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * <p>The RemoteControlClient must have been previously registered with 20511357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * {@link AudioManager#registerRemoteControlClient(RemoteControlClient)}.</p> 20521357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * 2053ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * @param rcc RemoteControlClient associated with this route 2054ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell */ 2055ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell public void setRemoteControlClient(RemoteControlClient rcc) { 2056ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell mRcc = rcc; 20571357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi updatePlaybackInfoOnRcc(); 2058ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell } 2059ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell 2060ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell /** 20614599696591f745b3a546197d2ba7e5cfc5562484Adam Powell * Retrieve the RemoteControlClient associated with this route, if one has been set. 20624599696591f745b3a546197d2ba7e5cfc5562484Adam Powell * 20634599696591f745b3a546197d2ba7e5cfc5562484Adam Powell * @return the RemoteControlClient associated with this route 20644599696591f745b3a546197d2ba7e5cfc5562484Adam Powell * @see #setRemoteControlClient(RemoteControlClient) 20654599696591f745b3a546197d2ba7e5cfc5562484Adam Powell */ 20664599696591f745b3a546197d2ba7e5cfc5562484Adam Powell public RemoteControlClient getRemoteControlClient() { 20674599696591f745b3a546197d2ba7e5cfc5562484Adam Powell return mRcc; 20684599696591f745b3a546197d2ba7e5cfc5562484Adam Powell } 20694599696591f745b3a546197d2ba7e5cfc5562484Adam Powell 20704599696591f745b3a546197d2ba7e5cfc5562484Adam Powell /** 2071ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * Set an icon that will be used to represent this route. 2072ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * The system may use this icon in picker UIs or similar. 2073ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * 2074ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * @param icon icon drawable to use to represent this route 2075ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell */ 2076ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell public void setIconDrawable(Drawable icon) { 2077ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell mIcon = icon; 2078ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell } 2079ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell 2080ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell /** 2081ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * Set an icon that will be used to represent this route. 2082ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * The system may use this icon in picker UIs or similar. 2083ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * 208471c69897ad0a55d590698bfa399bfe99c763b9dbAdam Powell * @param resId Resource ID of an icon drawable to use to represent this route 2085ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell */ 2086ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell public void setIconResource(int resId) { 2087ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell setIconDrawable(sStatic.mResources.getDrawable(resId)); 2088ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell } 20891357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 20901357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 20911357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * Set a callback to be notified of volume update requests 20921357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @param vcb 20931357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 20941357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public void setVolumeCallback(VolumeCallback vcb) { 20951357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi mVcb = new VolumeCallbackInfo(vcb, this); 20961357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 20971357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 20981357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 20991357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * Defines whether playback associated with this route is "local" 21001357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * ({@link RouteInfo#PLAYBACK_TYPE_LOCAL}) or "remote" 21011357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * ({@link RouteInfo#PLAYBACK_TYPE_REMOTE}). 21021357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @param type 21031357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 21041357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public void setPlaybackType(int type) { 21051357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi if (mPlaybackType != type) { 21061357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi mPlaybackType = type; 2107430fc48865e5a371b08f180390946b96d73848feRoboErik configureSessionVolume(); 21081357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 21091357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 21101357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 21111357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 21121357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * Defines whether volume for the playback associated with this route is fixed 21131357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * ({@link RouteInfo#PLAYBACK_VOLUME_FIXED}) or can modified 21141357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * ({@link RouteInfo#PLAYBACK_VOLUME_VARIABLE}). 21151357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @param volumeHandling 21161357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 21171357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public void setVolumeHandling(int volumeHandling) { 21181357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi if (mVolumeHandling != volumeHandling) { 21191357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi mVolumeHandling = volumeHandling; 2120430fc48865e5a371b08f180390946b96d73848feRoboErik configureSessionVolume(); 21211357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 21221357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 21231357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 21241357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 21251357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * Defines at what volume the playback associated with this route is performed (for user 21261357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * feedback purposes). This information is only used when the playback is not local. 21271357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @param volume 21281357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 21291357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public void setVolume(int volume) { 21308e37a85bf3dc39519942698dc90a3951306b934bAdam Powell volume = Math.max(0, Math.min(volume, getVolumeMax())); 21311357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi if (mVolume != volume) { 21321357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi mVolume = volume; 2133430fc48865e5a371b08f180390946b96d73848feRoboErik if (mSvp != null) { 21340d0f67f5ee5f939a1b611bc4583212707afd9beeRoboErik mSvp.setCurrentVolume(mVolume); 21355d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik } 21368e37a85bf3dc39519942698dc90a3951306b934bAdam Powell dispatchRouteVolumeChanged(this); 2137f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell if (mGroup != null) { 2138f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell mGroup.memberVolumeChanged(this); 2139f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell } 21408e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 21418e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 21428e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 21438e37a85bf3dc39519942698dc90a3951306b934bAdam Powell @Override 21448e37a85bf3dc39519942698dc90a3951306b934bAdam Powell public void requestSetVolume(int volume) { 21458e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (mVolumeHandling == PLAYBACK_VOLUME_VARIABLE) { 21468e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (mVcb == null) { 21478e37a85bf3dc39519942698dc90a3951306b934bAdam Powell Log.e(TAG, "Cannot requestSetVolume on user route - no volume callback set"); 21488e37a85bf3dc39519942698dc90a3951306b934bAdam Powell return; 21498e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 21508e37a85bf3dc39519942698dc90a3951306b934bAdam Powell mVcb.vcb.onVolumeSetRequest(this, volume); 21518e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 21528e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 21538e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 21548e37a85bf3dc39519942698dc90a3951306b934bAdam Powell @Override 21558e37a85bf3dc39519942698dc90a3951306b934bAdam Powell public void requestUpdateVolume(int direction) { 21568e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (mVolumeHandling == PLAYBACK_VOLUME_VARIABLE) { 21578e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (mVcb == null) { 21588e37a85bf3dc39519942698dc90a3951306b934bAdam Powell Log.e(TAG, "Cannot requestChangeVolume on user route - no volumec callback set"); 21598e37a85bf3dc39519942698dc90a3951306b934bAdam Powell return; 21608e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 21618e37a85bf3dc39519942698dc90a3951306b934bAdam Powell mVcb.vcb.onVolumeUpdateRequest(this, direction); 21621357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 21631357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 21641357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 21651357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 21661357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * Defines the maximum volume at which the playback associated with this route is performed 21671357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * (for user feedback purposes). This information is only used when the playback is not 21681357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * local. 21691357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @param volumeMax 21701357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 21711357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public void setVolumeMax(int volumeMax) { 21721357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi if (mVolumeMax != volumeMax) { 21731357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi mVolumeMax = volumeMax; 2174430fc48865e5a371b08f180390946b96d73848feRoboErik configureSessionVolume(); 21751357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 21761357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 21771357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 21781357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 21791357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * Defines over what stream type the media is presented. 21801357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @param stream 21811357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 21821357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public void setPlaybackStream(int stream) { 21831357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi if (mPlaybackStream != stream) { 21841357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi mPlaybackStream = stream; 2185430fc48865e5a371b08f180390946b96d73848feRoboErik configureSessionVolume(); 21861357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 21871357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 21881357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 21891357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi private void updatePlaybackInfoOnRcc() { 2190430fc48865e5a371b08f180390946b96d73848feRoboErik configureSessionVolume(); 21915d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik } 21925d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik 21935d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik private void configureSessionVolume() { 21945d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik if (mRcc == null) { 21955d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik if (DEBUG) { 21965d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik Log.d(TAG, "No Rcc to configure volume for route " + mName); 21975d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik } 21985d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik return; 21995d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik } 22005d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik MediaSession session = mRcc.getMediaSession(); 22015d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik if (session == null) { 22025d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik if (DEBUG) { 22035d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik Log.d(TAG, "Rcc has no session to configure volume"); 22045d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik } 22055d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik return; 22065d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik } 22075d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik if (mPlaybackType == RemoteControlClient.PLAYBACK_TYPE_REMOTE) { 2208ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik int volumeControl = VolumeProvider.VOLUME_CONTROL_FIXED; 22095d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik switch (mVolumeHandling) { 22105d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik case RemoteControlClient.PLAYBACK_VOLUME_VARIABLE: 2211ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik volumeControl = VolumeProvider.VOLUME_CONTROL_ABSOLUTE; 22125d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik break; 22135d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik case RemoteControlClient.PLAYBACK_VOLUME_FIXED: 22145d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik default: 22155d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik break; 22161357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 22175d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik // Only register a new listener if necessary 22185d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik if (mSvp == null || mSvp.getVolumeControl() != volumeControl 22195d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik || mSvp.getMaxVolume() != mVolumeMax) { 22200d0f67f5ee5f939a1b611bc4583212707afd9beeRoboErik mSvp = new SessionVolumeProvider(volumeControl, mVolumeMax, mVolume); 22215d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik session.setPlaybackToRemote(mSvp); 22225d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik } 22235d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik } else { 22245d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik // We only know how to handle local and remote, fall back to local if not remote. 22259db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik AudioAttributes.Builder bob = new AudioAttributes.Builder(); 22269db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik bob.setLegacyStreamType(mPlaybackStream); 22279db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik session.setPlaybackToLocal(bob.build()); 22285d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik mSvp = null; 22291357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 22301357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 22311357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 2232ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik class SessionVolumeProvider extends VolumeProvider { 22335d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik 22340d0f67f5ee5f939a1b611bc4583212707afd9beeRoboErik public SessionVolumeProvider(int volumeControl, int maxVolume, int currentVolume) { 22350d0f67f5ee5f939a1b611bc4583212707afd9beeRoboErik super(volumeControl, maxVolume, currentVolume); 22365d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik } 22375d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik 22385d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik @Override 22395d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik public void onSetVolumeTo(final int volume) { 22405d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik sStatic.mHandler.post(new Runnable() { 22415d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik @Override 22425d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik public void run() { 22435d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik if (mVcb != null) { 22445d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik mVcb.vcb.onVolumeSetRequest(mVcb.route, volume); 22455d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik } 22465d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik } 22475d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik }); 22485d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik } 22495d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik 22505d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik @Override 22511ff5b1648a051e9650614f0c0f1b3f449777db81RoboErik public void onAdjustVolume(final int direction) { 22525d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik sStatic.mHandler.post(new Runnable() { 22535d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik @Override 22545d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik public void run() { 22555d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik if (mVcb != null) { 22561ff5b1648a051e9650614f0c0f1b3f449777db81RoboErik mVcb.vcb.onVolumeUpdateRequest(mVcb.route, direction); 22575d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik } 22585d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik } 22595d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik }); 22605d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik } 22615d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik } 22629a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 22639a1de308cea2d160778fd977825f10a07b49d738Adam Powell 22649a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 22659a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Information about a route that consists of multiple other routes in a group. 22669a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 2267b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn public static class RouteGroup extends RouteInfo { 22689a1de308cea2d160778fd977825f10a07b49d738Adam Powell final ArrayList<RouteInfo> mRoutes = new ArrayList<RouteInfo>(); 22699a1de308cea2d160778fd977825f10a07b49d738Adam Powell private boolean mUpdateName; 22709a1de308cea2d160778fd977825f10a07b49d738Adam Powell 22719a1de308cea2d160778fd977825f10a07b49d738Adam Powell RouteGroup(RouteCategory category) { 22729a1de308cea2d160778fd977825f10a07b49d738Adam Powell super(category); 22739a1de308cea2d160778fd977825f10a07b49d738Adam Powell mGroup = this; 22748e37a85bf3dc39519942698dc90a3951306b934bAdam Powell mVolumeHandling = PLAYBACK_VOLUME_FIXED; 22759a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 22769a1de308cea2d160778fd977825f10a07b49d738Adam Powell 227769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown @Override 22780d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell CharSequence getName(Resources res) { 22799a1de308cea2d160778fd977825f10a07b49d738Adam Powell if (mUpdateName) updateName(); 22800d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell return super.getName(res); 22819a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 22829a1de308cea2d160778fd977825f10a07b49d738Adam Powell 22839a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 22849a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Add a route to this group. The route must not currently belong to another group. 22859a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 22869a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param route route to add to this group 22879a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 22889a1de308cea2d160778fd977825f10a07b49d738Adam Powell public void addRoute(RouteInfo route) { 22899a1de308cea2d160778fd977825f10a07b49d738Adam Powell if (route.getGroup() != null) { 22909a1de308cea2d160778fd977825f10a07b49d738Adam Powell throw new IllegalStateException("Route " + route + " is already part of a group."); 22919a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 22929a1de308cea2d160778fd977825f10a07b49d738Adam Powell if (route.getCategory() != mCategory) { 22939a1de308cea2d160778fd977825f10a07b49d738Adam Powell throw new IllegalArgumentException( 22949a1de308cea2d160778fd977825f10a07b49d738Adam Powell "Route cannot be added to a group with a different category. " + 22959a1de308cea2d160778fd977825f10a07b49d738Adam Powell "(Route category=" + route.getCategory() + 22969a1de308cea2d160778fd977825f10a07b49d738Adam Powell " group category=" + mCategory + ")"); 22979a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 2298d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell final int at = mRoutes.size(); 22999a1de308cea2d160778fd977825f10a07b49d738Adam Powell mRoutes.add(route); 2300d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell route.mGroup = this; 23019a1de308cea2d160778fd977825f10a07b49d738Adam Powell mUpdateName = true; 2302f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell updateVolume(); 23039a1de308cea2d160778fd977825f10a07b49d738Adam Powell routeUpdated(); 2304f3b653a21cdffe04c94c275e69ecb56e00766e82Adam Powell dispatchRouteGrouped(route, this, at); 23059a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 23069a1de308cea2d160778fd977825f10a07b49d738Adam Powell 23079a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 23089a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Add a route to this group before the specified index. 23099a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 23109a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param route route to add 23119a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param insertAt insert the new route before this index 23129a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 23139a1de308cea2d160778fd977825f10a07b49d738Adam Powell public void addRoute(RouteInfo route, int insertAt) { 23149a1de308cea2d160778fd977825f10a07b49d738Adam Powell if (route.getGroup() != null) { 23159a1de308cea2d160778fd977825f10a07b49d738Adam Powell throw new IllegalStateException("Route " + route + " is already part of a group."); 23169a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 23179a1de308cea2d160778fd977825f10a07b49d738Adam Powell if (route.getCategory() != mCategory) { 23189a1de308cea2d160778fd977825f10a07b49d738Adam Powell throw new IllegalArgumentException( 23199a1de308cea2d160778fd977825f10a07b49d738Adam Powell "Route cannot be added to a group with a different category. " + 23209a1de308cea2d160778fd977825f10a07b49d738Adam Powell "(Route category=" + route.getCategory() + 23219a1de308cea2d160778fd977825f10a07b49d738Adam Powell " group category=" + mCategory + ")"); 23229a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 23239a1de308cea2d160778fd977825f10a07b49d738Adam Powell mRoutes.add(insertAt, route); 2324d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell route.mGroup = this; 23259a1de308cea2d160778fd977825f10a07b49d738Adam Powell mUpdateName = true; 2326f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell updateVolume(); 23279a1de308cea2d160778fd977825f10a07b49d738Adam Powell routeUpdated(); 2328f3b653a21cdffe04c94c275e69ecb56e00766e82Adam Powell dispatchRouteGrouped(route, this, insertAt); 23299a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 23309a1de308cea2d160778fd977825f10a07b49d738Adam Powell 23319a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 23329a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Remove a route from this group. 23339a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 23349a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param route route to remove 23359a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 23369a1de308cea2d160778fd977825f10a07b49d738Adam Powell public void removeRoute(RouteInfo route) { 23379a1de308cea2d160778fd977825f10a07b49d738Adam Powell if (route.getGroup() != this) { 23389a1de308cea2d160778fd977825f10a07b49d738Adam Powell throw new IllegalArgumentException("Route " + route + 23399a1de308cea2d160778fd977825f10a07b49d738Adam Powell " is not a member of this group."); 23409a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 23419a1de308cea2d160778fd977825f10a07b49d738Adam Powell mRoutes.remove(route); 2342d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell route.mGroup = null; 23439a1de308cea2d160778fd977825f10a07b49d738Adam Powell mUpdateName = true; 2344f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell updateVolume(); 2345d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell dispatchRouteUngrouped(route, this); 23469a1de308cea2d160778fd977825f10a07b49d738Adam Powell routeUpdated(); 23479a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 23489a1de308cea2d160778fd977825f10a07b49d738Adam Powell 23499a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 23509a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Remove the route at the specified index from this group. 23519a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 23529a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param index index of the route to remove 23539a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 23549a1de308cea2d160778fd977825f10a07b49d738Adam Powell public void removeRoute(int index) { 2355d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell RouteInfo route = mRoutes.remove(index); 2356d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell route.mGroup = null; 23579a1de308cea2d160778fd977825f10a07b49d738Adam Powell mUpdateName = true; 2358f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell updateVolume(); 2359d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell dispatchRouteUngrouped(route, this); 23609a1de308cea2d160778fd977825f10a07b49d738Adam Powell routeUpdated(); 23619a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 23629a1de308cea2d160778fd977825f10a07b49d738Adam Powell 2363d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell /** 2364d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @return The number of routes in this group 2365d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell */ 2366d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell public int getRouteCount() { 2367d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell return mRoutes.size(); 2368d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell } 2369d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell 2370d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell /** 2371d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * Return the route in this group at the specified index 2372d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * 2373d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param index Index to fetch 2374d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @return The route at index 2375d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell */ 2376d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell public RouteInfo getRouteAt(int index) { 2377d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell return mRoutes.get(index); 2378d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell } 2379d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell 2380ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell /** 2381ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * Set an icon that will be used to represent this group. 2382ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * The system may use this icon in picker UIs or similar. 2383ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * 2384ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * @param icon icon drawable to use to represent this group 2385ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell */ 2386ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell public void setIconDrawable(Drawable icon) { 2387ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell mIcon = icon; 2388ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell } 2389ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell 2390ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell /** 2391ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * Set an icon that will be used to represent this group. 2392ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * The system may use this icon in picker UIs or similar. 2393ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * 239471c69897ad0a55d590698bfa399bfe99c763b9dbAdam Powell * @param resId Resource ID of an icon drawable to use to represent this group 2395ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell */ 2396ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell public void setIconResource(int resId) { 2397ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell setIconDrawable(sStatic.mResources.getDrawable(resId)); 2398ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell } 2399ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell 24008e37a85bf3dc39519942698dc90a3951306b934bAdam Powell @Override 24018e37a85bf3dc39519942698dc90a3951306b934bAdam Powell public void requestSetVolume(int volume) { 24028e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final int maxVol = getVolumeMax(); 24038e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (maxVol == 0) { 24048e37a85bf3dc39519942698dc90a3951306b934bAdam Powell return; 24058e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 24068e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 24078e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final float scaledVolume = (float) volume / maxVol; 24088e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final int routeCount = getRouteCount(); 24098e37a85bf3dc39519942698dc90a3951306b934bAdam Powell for (int i = 0; i < routeCount; i++) { 24108e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final RouteInfo route = getRouteAt(i); 24118e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final int routeVol = (int) (scaledVolume * route.getVolumeMax()); 24128e37a85bf3dc39519942698dc90a3951306b934bAdam Powell route.requestSetVolume(routeVol); 24138e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 24148e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (volume != mVolume) { 24158e37a85bf3dc39519942698dc90a3951306b934bAdam Powell mVolume = volume; 24168e37a85bf3dc39519942698dc90a3951306b934bAdam Powell dispatchRouteVolumeChanged(this); 24178e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 24188e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 24198e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 24208e37a85bf3dc39519942698dc90a3951306b934bAdam Powell @Override 24218e37a85bf3dc39519942698dc90a3951306b934bAdam Powell public void requestUpdateVolume(int direction) { 24228e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final int maxVol = getVolumeMax(); 24238e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (maxVol == 0) { 24248e37a85bf3dc39519942698dc90a3951306b934bAdam Powell return; 24258e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 24268e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 24278e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final int routeCount = getRouteCount(); 2428f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell int volume = 0; 24298e37a85bf3dc39519942698dc90a3951306b934bAdam Powell for (int i = 0; i < routeCount; i++) { 24308e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final RouteInfo route = getRouteAt(i); 24318e37a85bf3dc39519942698dc90a3951306b934bAdam Powell route.requestUpdateVolume(direction); 2432f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell final int routeVol = route.getVolume(); 2433f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell if (routeVol > volume) { 2434f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell volume = routeVol; 2435f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell } 24368e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 24378e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (volume != mVolume) { 24388e37a85bf3dc39519942698dc90a3951306b934bAdam Powell mVolume = volume; 24398e37a85bf3dc39519942698dc90a3951306b934bAdam Powell dispatchRouteVolumeChanged(this); 24408e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 24418e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 24428e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 24439a1de308cea2d160778fd977825f10a07b49d738Adam Powell void memberNameChanged(RouteInfo info, CharSequence name) { 24449a1de308cea2d160778fd977825f10a07b49d738Adam Powell mUpdateName = true; 24459a1de308cea2d160778fd977825f10a07b49d738Adam Powell routeUpdated(); 24469a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 24479a1de308cea2d160778fd977825f10a07b49d738Adam Powell 24489a1de308cea2d160778fd977825f10a07b49d738Adam Powell void memberStatusChanged(RouteInfo info, CharSequence status) { 24499a1de308cea2d160778fd977825f10a07b49d738Adam Powell setStatusInt(status); 24509a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 24519a1de308cea2d160778fd977825f10a07b49d738Adam Powell 2452f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell void memberVolumeChanged(RouteInfo info) { 2453f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell updateVolume(); 2454f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell } 2455f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell 2456f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell void updateVolume() { 2457f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell // A group always represents the highest component volume value. 2458f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell final int routeCount = getRouteCount(); 2459f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell int volume = 0; 2460f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell for (int i = 0; i < routeCount; i++) { 2461f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell final int routeVol = getRouteAt(i).getVolume(); 2462f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell if (routeVol > volume) { 2463f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell volume = routeVol; 2464f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell } 2465f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell } 2466f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell if (volume != mVolume) { 2467f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell mVolume = volume; 2468f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell dispatchRouteVolumeChanged(this); 2469f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell } 2470f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell } 2471f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell 2472d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell @Override 2473d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell void routeUpdated() { 2474d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell int types = 0; 2475d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell final int count = mRoutes.size(); 2476b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell if (count == 0) { 2477b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell // Don't keep empty groups in the router. 247869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown MediaRouter.removeRouteStatic(this); 2479b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell return; 2480b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell } 2481b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell 24828e37a85bf3dc39519942698dc90a3951306b934bAdam Powell int maxVolume = 0; 24838e37a85bf3dc39519942698dc90a3951306b934bAdam Powell boolean isLocal = true; 24848e37a85bf3dc39519942698dc90a3951306b934bAdam Powell boolean isFixedVolume = true; 2485d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell for (int i = 0; i < count; i++) { 24868e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final RouteInfo route = mRoutes.get(i); 24878e37a85bf3dc39519942698dc90a3951306b934bAdam Powell types |= route.mSupportedTypes; 24888e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final int routeMaxVolume = route.getVolumeMax(); 24898e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (routeMaxVolume > maxVolume) { 24908e37a85bf3dc39519942698dc90a3951306b934bAdam Powell maxVolume = routeMaxVolume; 24918e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 24928e37a85bf3dc39519942698dc90a3951306b934bAdam Powell isLocal &= route.getPlaybackType() == PLAYBACK_TYPE_LOCAL; 24938e37a85bf3dc39519942698dc90a3951306b934bAdam Powell isFixedVolume &= route.getVolumeHandling() == PLAYBACK_VOLUME_FIXED; 2494d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell } 24958e37a85bf3dc39519942698dc90a3951306b934bAdam Powell mPlaybackType = isLocal ? PLAYBACK_TYPE_LOCAL : PLAYBACK_TYPE_REMOTE; 24968e37a85bf3dc39519942698dc90a3951306b934bAdam Powell mVolumeHandling = isFixedVolume ? PLAYBACK_VOLUME_FIXED : PLAYBACK_VOLUME_VARIABLE; 2497d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell mSupportedTypes = types; 24988e37a85bf3dc39519942698dc90a3951306b934bAdam Powell mVolumeMax = maxVolume; 2499d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell mIcon = count == 1 ? mRoutes.get(0).getIconDrawable() : null; 2500d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell super.routeUpdated(); 2501d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell } 2502d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell 25039a1de308cea2d160778fd977825f10a07b49d738Adam Powell void updateName() { 25049a1de308cea2d160778fd977825f10a07b49d738Adam Powell final StringBuilder sb = new StringBuilder(); 25059a1de308cea2d160778fd977825f10a07b49d738Adam Powell final int count = mRoutes.size(); 25069a1de308cea2d160778fd977825f10a07b49d738Adam Powell for (int i = 0; i < count; i++) { 25079a1de308cea2d160778fd977825f10a07b49d738Adam Powell final RouteInfo info = mRoutes.get(i); 2508b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell // TODO: There's probably a much more correct way to localize this. 25099a1de308cea2d160778fd977825f10a07b49d738Adam Powell if (i > 0) sb.append(", "); 25109a1de308cea2d160778fd977825f10a07b49d738Adam Powell sb.append(info.mName); 25119a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 25129a1de308cea2d160778fd977825f10a07b49d738Adam Powell mName = sb.toString(); 25139a1de308cea2d160778fd977825f10a07b49d738Adam Powell mUpdateName = false; 25149a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 2515d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell 2516d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell @Override 2517d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell public String toString() { 2518d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell StringBuilder sb = new StringBuilder(super.toString()); 2519d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell sb.append('['); 2520d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell final int count = mRoutes.size(); 2521d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell for (int i = 0; i < count; i++) { 2522d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell if (i > 0) sb.append(", "); 2523d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell sb.append(mRoutes.get(i)); 2524d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell } 2525d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell sb.append(']'); 2526d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell return sb.toString(); 2527d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell } 25289a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 25299a1de308cea2d160778fd977825f10a07b49d738Adam Powell 25309a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 25319a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Definition of a category of routes. All routes belong to a category. 25329a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 2533b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn public static class RouteCategory { 25349a1de308cea2d160778fd977825f10a07b49d738Adam Powell CharSequence mName; 25350d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell int mNameResId; 25369a1de308cea2d160778fd977825f10a07b49d738Adam Powell int mTypes; 25379a1de308cea2d160778fd977825f10a07b49d738Adam Powell final boolean mGroupable; 2538705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell boolean mIsSystem; 25399a1de308cea2d160778fd977825f10a07b49d738Adam Powell 25409a1de308cea2d160778fd977825f10a07b49d738Adam Powell RouteCategory(CharSequence name, int types, boolean groupable) { 25419a1de308cea2d160778fd977825f10a07b49d738Adam Powell mName = name; 25429a1de308cea2d160778fd977825f10a07b49d738Adam Powell mTypes = types; 25439a1de308cea2d160778fd977825f10a07b49d738Adam Powell mGroupable = groupable; 25449a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 25459a1de308cea2d160778fd977825f10a07b49d738Adam Powell 25460d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell RouteCategory(int nameResId, int types, boolean groupable) { 25470d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell mNameResId = nameResId; 25480d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell mTypes = types; 25490d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell mGroupable = groupable; 25500d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell } 25510d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell 25529a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 25539a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @return the name of this route category 25549a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 25559a1de308cea2d160778fd977825f10a07b49d738Adam Powell public CharSequence getName() { 25560d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell return getName(sStatic.mResources); 25570d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell } 25585d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik 25590d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell /** 25600d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * Return the properly localized/configuration dependent name of this RouteCategory. 25615d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik * 25620d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * @param context Context to resolve name resources 25630d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * @return the name of this route category 25640d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell */ 25650d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public CharSequence getName(Context context) { 25660d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell return getName(context.getResources()); 25670d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell } 25685d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik 25690d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell CharSequence getName(Resources res) { 25700d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell if (mNameResId != 0) { 25710d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell return res.getText(mNameResId); 25720d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell } 25739a1de308cea2d160778fd977825f10a07b49d738Adam Powell return mName; 25749a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 25759a1de308cea2d160778fd977825f10a07b49d738Adam Powell 25769a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 2577d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * Return the current list of routes in this category that have been added 2578d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * to the MediaRouter. 25799a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 2580d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * <p>This list will not include routes that are nested within RouteGroups. 2581d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * A RouteGroup is treated as a single route within its category.</p> 2582d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * 2583d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param out a List to fill with the routes in this category. If this parameter is 2584d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * non-null, it will be cleared, filled with the current routes with this 2585d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * category, and returned. If this parameter is null, a new List will be 2586d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * allocated to report the category's current routes. 2587d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @return A list with the routes in this category that have been added to the MediaRouter. 25889a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 2589d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell public List<RouteInfo> getRoutes(List<RouteInfo> out) { 2590d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell if (out == null) { 2591d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell out = new ArrayList<RouteInfo>(); 2592d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell } else { 2593d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell out.clear(); 2594d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell } 2595d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell 2596b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn final int count = getRouteCountStatic(); 2597d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell for (int i = 0; i < count; i++) { 2598b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn final RouteInfo route = getRouteAtStatic(i); 2599d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell if (route.mCategory == this) { 2600d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell out.add(route); 2601d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell } 2602d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell } 2603d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell return out; 26049a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 26059a1de308cea2d160778fd977825f10a07b49d738Adam Powell 26069a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 26079a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @return Flag set describing the route types supported by this category 26089a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 26099a1de308cea2d160778fd977825f10a07b49d738Adam Powell public int getSupportedTypes() { 26109a1de308cea2d160778fd977825f10a07b49d738Adam Powell return mTypes; 26119a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 26129a1de308cea2d160778fd977825f10a07b49d738Adam Powell 26139a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 26149a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Return whether or not this category supports grouping. 26159a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 26169a1de308cea2d160778fd977825f10a07b49d738Adam Powell * <p>If this method returns true, all routes obtained from this category 2617d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * via calls to {@link #getRouteAt(int)} will be {@link MediaRouter.RouteGroup}s.</p> 26189a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 26199a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @return true if this category supports 26209a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 26219a1de308cea2d160778fd977825f10a07b49d738Adam Powell public boolean isGroupable() { 26229a1de308cea2d160778fd977825f10a07b49d738Adam Powell return mGroupable; 26239a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 26249a1de308cea2d160778fd977825f10a07b49d738Adam Powell 2625705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell /** 2626705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell * @return true if this is the category reserved for system routes. 2627705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell * @hide 2628705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell */ 2629705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell public boolean isSystem() { 2630705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell return mIsSystem; 2631705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 2632705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 263369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown @Override 26349a1de308cea2d160778fd977825f10a07b49d738Adam Powell public String toString() { 26359a1de308cea2d160778fd977825f10a07b49d738Adam Powell return "RouteCategory{ name=" + mName + " types=" + typesToString(mTypes) + 2636d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell " groupable=" + mGroupable + " }"; 26379a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 26389a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 26399a1de308cea2d160778fd977825f10a07b49d738Adam Powell 26409a1de308cea2d160778fd977825f10a07b49d738Adam Powell static class CallbackInfo { 26419a1de308cea2d160778fd977825f10a07b49d738Adam Powell public int type; 264266f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown public int flags; 2643b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn public final Callback cb; 2644b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn public final MediaRouter router; 26459a1de308cea2d160778fd977825f10a07b49d738Adam Powell 264666f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown public CallbackInfo(Callback cb, int type, int flags, MediaRouter router) { 26479a1de308cea2d160778fd977825f10a07b49d738Adam Powell this.cb = cb; 26489a1de308cea2d160778fd977825f10a07b49d738Adam Powell this.type = type; 264966f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown this.flags = flags; 2650b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn this.router = router; 26519a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 265266f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown 265366f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown public boolean filterRouteEvent(RouteInfo route) { 2654af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown return filterRouteEvent(route.mSupportedTypes); 2655af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown } 2656af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown 2657af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown public boolean filterRouteEvent(int supportedTypes) { 265866f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown return (flags & CALLBACK_FLAG_UNFILTERED_EVENTS) != 0 2659af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown || (type & supportedTypes) != 0; 266066f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown } 26619a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 26629a1de308cea2d160778fd977825f10a07b49d738Adam Powell 26639a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 26649a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Interface for receiving events about media routing changes. 26659a1de308cea2d160778fd977825f10a07b49d738Adam Powell * All methods of this interface will be called from the application's main thread. 266666f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * <p> 266766f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * A Callback will only receive events relevant to routes that the callback 266866f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * was registered for unless the {@link MediaRouter#CALLBACK_FLAG_UNFILTERED_EVENTS} 266966f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * flag was specified in {@link MediaRouter#addCallback(int, Callback, int)}. 267066f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * </p> 26719a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 267266f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * @see MediaRouter#addCallback(int, Callback, int) 26739a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @see MediaRouter#removeCallback(Callback) 26749a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 26750d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public static abstract class Callback { 26769a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 26779a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Called when the supplied route becomes selected as the active route 26789a1de308cea2d160778fd977825f10a07b49d738Adam Powell * for the given route type. 26799a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 2680d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param router the MediaRouter reporting the event 26819a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param type Type flag set indicating the routes that have been selected 26829a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param info Route that has been selected for the given route types 26839a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 26840d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public abstract void onRouteSelected(MediaRouter router, int type, RouteInfo info); 26859a1de308cea2d160778fd977825f10a07b49d738Adam Powell 26869a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 26879a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Called when the supplied route becomes unselected as the active route 26889a1de308cea2d160778fd977825f10a07b49d738Adam Powell * for the given route type. 26899a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 2690d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param router the MediaRouter reporting the event 26919a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param type Type flag set indicating the routes that have been unselected 26929a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param info Route that has been unselected for the given route types 26939a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 26940d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public abstract void onRouteUnselected(MediaRouter router, int type, RouteInfo info); 26959a1de308cea2d160778fd977825f10a07b49d738Adam Powell 26969a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 26979a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Called when a route for the specified type was added. 26989a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 2699d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param router the MediaRouter reporting the event 27009a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param info Route that has become available for use 27019a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 27020d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public abstract void onRouteAdded(MediaRouter router, RouteInfo info); 27039a1de308cea2d160778fd977825f10a07b49d738Adam Powell 27049a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 27059a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Called when a route for the specified type was removed. 27069a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 2707d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param router the MediaRouter reporting the event 27089a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param info Route that has been removed from availability 27099a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 27100d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public abstract void onRouteRemoved(MediaRouter router, RouteInfo info); 27119a1de308cea2d160778fd977825f10a07b49d738Adam Powell 27129a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 27139a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Called when an aspect of the indicated route has changed. 27149a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 27159a1de308cea2d160778fd977825f10a07b49d738Adam Powell * <p>This will not indicate that the types supported by this route have 27169a1de308cea2d160778fd977825f10a07b49d738Adam Powell * changed, only that cosmetic info such as name or status have been updated.</p> 27179a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 2718d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param router the MediaRouter reporting the event 27199a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param info The route that was changed 27209a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 27210d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public abstract void onRouteChanged(MediaRouter router, RouteInfo info); 2722d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell 2723d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell /** 2724d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * Called when a route is added to a group. 2725d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * 2726d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param router the MediaRouter reporting the event 2727d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param info The route that was added 2728d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param group The group the route was added to 2729d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param index The route index within group that info was added at 2730d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell */ 27310d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public abstract void onRouteGrouped(MediaRouter router, RouteInfo info, RouteGroup group, 27320d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell int index); 2733d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell 2734d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell /** 2735d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * Called when a route is removed from a group. 2736d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * 2737d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param router the MediaRouter reporting the event 2738d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param info The route that was removed 2739d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param group The group the route was removed from 2740d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell */ 27410d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public abstract void onRouteUngrouped(MediaRouter router, RouteInfo info, RouteGroup group); 27428e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 27438e37a85bf3dc39519942698dc90a3951306b934bAdam Powell /** 27448e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * Called when a route's volume changes. 27458e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * 27468e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * @param router the MediaRouter reporting the event 27478e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * @param info The route with altered volume 27488e37a85bf3dc39519942698dc90a3951306b934bAdam Powell */ 27498e37a85bf3dc39519942698dc90a3951306b934bAdam Powell public abstract void onRouteVolumeChanged(MediaRouter router, RouteInfo info); 275092130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown 275192130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown /** 275292130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * Called when a route's presentation display changes. 275392130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * <p> 275492130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * This method is called whenever the route's presentation display becomes 275592130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * available, is removes or has changes to some of its properties (such as its size). 275692130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * </p> 275792130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * 275892130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * @param router the MediaRouter reporting the event 275992130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * @param info The route whose presentation display changed 276092130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * 276192130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * @see RouteInfo#getPresentationDisplay() 276292130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown */ 276392130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown public void onRoutePresentationDisplayChanged(MediaRouter router, RouteInfo info) { 276492130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown } 27659a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 27669a1de308cea2d160778fd977825f10a07b49d738Adam Powell 27679a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 27680d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * Stub implementation of {@link MediaRouter.Callback}. 27690d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * Each abstract method is defined as a no-op. Override just the ones 27709a1de308cea2d160778fd977825f10a07b49d738Adam Powell * you need. 27719a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 27720d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public static class SimpleCallback extends Callback { 27739a1de308cea2d160778fd977825f10a07b49d738Adam Powell 27749a1de308cea2d160778fd977825f10a07b49d738Adam Powell @Override 2775d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell public void onRouteSelected(MediaRouter router, int type, RouteInfo info) { 27769a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 27779a1de308cea2d160778fd977825f10a07b49d738Adam Powell 27789a1de308cea2d160778fd977825f10a07b49d738Adam Powell @Override 2779d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell public void onRouteUnselected(MediaRouter router, int type, RouteInfo info) { 27809a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 27819a1de308cea2d160778fd977825f10a07b49d738Adam Powell 27829a1de308cea2d160778fd977825f10a07b49d738Adam Powell @Override 2783d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell public void onRouteAdded(MediaRouter router, RouteInfo info) { 27849a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 27859a1de308cea2d160778fd977825f10a07b49d738Adam Powell 27869a1de308cea2d160778fd977825f10a07b49d738Adam Powell @Override 2787d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell public void onRouteRemoved(MediaRouter router, RouteInfo info) { 27889a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 27899a1de308cea2d160778fd977825f10a07b49d738Adam Powell 27909a1de308cea2d160778fd977825f10a07b49d738Adam Powell @Override 2791d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell public void onRouteChanged(MediaRouter router, RouteInfo info) { 27929a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 27939a1de308cea2d160778fd977825f10a07b49d738Adam Powell 27949a1de308cea2d160778fd977825f10a07b49d738Adam Powell @Override 2795d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell public void onRouteGrouped(MediaRouter router, RouteInfo info, RouteGroup group, 2796d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell int index) { 27979a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 27989a1de308cea2d160778fd977825f10a07b49d738Adam Powell 27999a1de308cea2d160778fd977825f10a07b49d738Adam Powell @Override 2800d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell public void onRouteUngrouped(MediaRouter router, RouteInfo info, RouteGroup group) { 28019a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 2802d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell 28038e37a85bf3dc39519942698dc90a3951306b934bAdam Powell @Override 28048e37a85bf3dc39519942698dc90a3951306b934bAdam Powell public void onRouteVolumeChanged(MediaRouter router, RouteInfo info) { 28058e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 28069a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 28071357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 28081357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi static class VolumeCallbackInfo { 28091357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public final VolumeCallback vcb; 28101357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public final RouteInfo route; 28111357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 28121357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public VolumeCallbackInfo(VolumeCallback vcb, RouteInfo route) { 28131357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi this.vcb = vcb; 28141357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi this.route = route; 28151357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 28161357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 28171357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 28181357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 28191357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * Interface for receiving events about volume changes. 28201357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * All methods of this interface will be called from the application's main thread. 28211357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * 28221357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * <p>A VolumeCallback will only receive events relevant to routes that the callback 28231357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * was registered for.</p> 28241357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * 28251357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @see UserRouteInfo#setVolumeCallback(VolumeCallback) 28261357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 28271357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public static abstract class VolumeCallback { 28281357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 28291357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * Called when the volume for the route should be increased or decreased. 28301357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @param info the route affected by this event 28311357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @param direction an integer indicating whether the volume is to be increased 28321357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * (positive value) or decreased (negative value). 28331357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * For bundled changes, the absolute value indicates the number of changes 28341357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * in the same direction, e.g. +3 corresponds to three "volume up" changes. 28351357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 28361357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public abstract void onVolumeUpdateRequest(RouteInfo info, int direction); 28371357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 28381357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * Called when the volume for the route should be set to the given value 28391357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @param info the route affected by this event 28401357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @param volume an integer indicating the new volume value that should be used, always 28411357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * between 0 and the value set by {@link UserRouteInfo#setVolumeMax(int)}. 28421357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 28431357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public abstract void onVolumeSetRequest(RouteInfo info, int volume); 28441357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 28451357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 28468e37a85bf3dc39519942698dc90a3951306b934bAdam Powell static class VolumeChangeReceiver extends BroadcastReceiver { 28478e37a85bf3dc39519942698dc90a3951306b934bAdam Powell @Override 28488e37a85bf3dc39519942698dc90a3951306b934bAdam Powell public void onReceive(Context context, Intent intent) { 28498e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (intent.getAction().equals(AudioManager.VOLUME_CHANGED_ACTION)) { 28508e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final int streamType = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, 28518e37a85bf3dc39519942698dc90a3951306b934bAdam Powell -1); 28528e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (streamType != AudioManager.STREAM_MUSIC) { 28538e37a85bf3dc39519942698dc90a3951306b934bAdam Powell return; 28548e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 28558e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 28568e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final int newVolume = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, 0); 28578e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final int oldVolume = intent.getIntExtra( 28588e37a85bf3dc39519942698dc90a3951306b934bAdam Powell AudioManager.EXTRA_PREV_VOLUME_STREAM_VALUE, 0); 28598e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (newVolume != oldVolume) { 28608e37a85bf3dc39519942698dc90a3951306b934bAdam Powell systemVolumeChanged(newVolume); 28618e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 28628e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 28638e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 2864705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 28658e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 2866705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell static class WifiDisplayStatusChangedReceiver extends BroadcastReceiver { 2867705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell @Override 2868705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell public void onReceive(Context context, Intent intent) { 2869705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell if (intent.getAction().equals(DisplayManager.ACTION_WIFI_DISPLAY_STATUS_CHANGED)) { 2870705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell updateWifiDisplayStatus((WifiDisplayStatus) intent.getParcelableExtra( 2871705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell DisplayManager.EXTRA_WIFI_DISPLAY_STATUS)); 2872705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 2873705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 28748e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 28759a1de308cea2d160778fd977825f10a07b49d738Adam Powell} 2876