MediaRouter.java revision fa6f70e225a7370c1ecb21ee7076c9086ecb9e9a
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; 207b9c912f536925ac6ec43935d6e97506851b33d6Tor Norbyeimport android.annotation.DrawableRes; 219dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kangimport android.annotation.IntDef; 229d93a378c5158d14f80d46af70433234330ec568P.Y. Laligandimport android.annotation.NonNull; 23ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackbornimport android.app.ActivityThread; 248e37a85bf3dc39519942698dc90a3951306b934bAdam Powellimport android.content.BroadcastReceiver; 259a1de308cea2d160778fd977825f10a07b49d738Adam Powellimport android.content.Context; 268e37a85bf3dc39519942698dc90a3951306b934bAdam Powellimport android.content.Intent; 278e37a85bf3dc39519942698dc90a3951306b934bAdam Powellimport android.content.IntentFilter; 28af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brownimport android.content.pm.PackageManager; 29b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackbornimport android.content.res.Resources; 30ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powellimport android.graphics.drawable.Drawable; 31705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powellimport android.hardware.display.DisplayManager; 32705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powellimport android.hardware.display.WifiDisplay; 33705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powellimport android.hardware.display.WifiDisplayStatus; 345d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErikimport android.media.session.MediaSession; 359a1de308cea2d160778fd977825f10a07b49d738Adam Powellimport android.os.Handler; 36632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackbornimport android.os.IBinder; 37af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brownimport android.os.Process; 38632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackbornimport android.os.RemoteException; 39632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackbornimport android.os.ServiceManager; 4069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brownimport android.os.UserHandle; 41632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackbornimport android.text.TextUtils; 429a1de308cea2d160778fd977825f10a07b49d738Adam Powellimport android.util.Log; 43705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powellimport android.view.Display; 449a1de308cea2d160778fd977825f10a07b49d738Adam Powell 459dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kangimport java.lang.annotation.Retention; 469dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kangimport java.lang.annotation.RetentionPolicy; 479a1de308cea2d160778fd977825f10a07b49d738Adam Powellimport java.util.ArrayList; 489a1de308cea2d160778fd977825f10a07b49d738Adam Powellimport java.util.HashMap; 49d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powellimport java.util.List; 50e6585b32ea586743258a5457e2184ffc087f2d2fKenny Rootimport java.util.Objects; 5139d5c6172503620ac3761148adac5fd7fa20d02dAdam Powellimport java.util.concurrent.CopyOnWriteArrayList; 529a1de308cea2d160778fd977825f10a07b49d738Adam Powell 539a1de308cea2d160778fd977825f10a07b49d738Adam Powell/** 549a1de308cea2d160778fd977825f10a07b49d738Adam Powell * MediaRouter allows applications to control the routing of media channels 559a1de308cea2d160778fd977825f10a07b49d738Adam Powell * and streams from the current device to external speakers and destination devices. 569a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 57b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn * <p>A MediaRouter is retrieved through {@link Context#getSystemService(String) 58b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn * Context.getSystemService()} of a {@link Context#MEDIA_ROUTER_SERVICE 59b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn * Context.MEDIA_ROUTER_SERVICE}. 60b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn * 61b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn * <p>The media router API is not thread-safe; all interactions with it must be 62b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn * done from the main thread of the process.</p> 639a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 649a1de308cea2d160778fd977825f10a07b49d738Adam Powellpublic class MediaRouter { 659a1de308cea2d160778fd977825f10a07b49d738Adam Powell private static final String TAG = "MediaRouter"; 6669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); 679a1de308cea2d160778fd977825f10a07b49d738Adam Powell 6892130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown static class Static implements DisplayManager.DisplayListener { 6969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final Context mAppContext; 70b35c445f34e1a18e17aef3e3dfbc1c39b4d1815cAdam Powell final Resources mResources; 71632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn final IAudioService mAudioService; 72705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell final DisplayManager mDisplayService; 7369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final IMediaRouterService mMediaRouterService; 74b35c445f34e1a18e17aef3e3dfbc1c39b4d1815cAdam Powell final Handler mHandler; 7539d5c6172503620ac3761148adac5fd7fa20d02dAdam Powell final CopyOnWriteArrayList<CallbackInfo> mCallbacks = 7639d5c6172503620ac3761148adac5fd7fa20d02dAdam Powell new CopyOnWriteArrayList<CallbackInfo>(); 77b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn 78b35c445f34e1a18e17aef3e3dfbc1c39b4d1815cAdam Powell final ArrayList<RouteInfo> mRoutes = new ArrayList<RouteInfo>(); 79b35c445f34e1a18e17aef3e3dfbc1c39b4d1815cAdam Powell final ArrayList<RouteCategory> mCategories = new ArrayList<RouteCategory>(); 80b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn 81b35c445f34e1a18e17aef3e3dfbc1c39b4d1815cAdam Powell final RouteCategory mSystemCategory; 82632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn 83705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell final AudioRoutesInfo mCurAudioRoutesInfo = new AudioRoutesInfo(); 84b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn 85705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell RouteInfo mDefaultAudioVideo; 86b35c445f34e1a18e17aef3e3dfbc1c39b4d1815cAdam Powell RouteInfo mBluetoothA2dpRoute; 87b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn 88b35c445f34e1a18e17aef3e3dfbc1c39b4d1815cAdam Powell RouteInfo mSelectedRoute; 899a1de308cea2d160778fd977825f10a07b49d738Adam Powell 90af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown final boolean mCanConfigureWifiDisplays; 9166f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown boolean mActivelyScanningWifiDisplays; 92ce468a35b388ca46578934706b38dbae94941643Jeff Brown String mPreviousActiveWifiDisplayAddress; 93705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 9469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown int mDiscoveryRequestRouteTypes; 9569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown boolean mDiscoverRequestActiveScan; 9669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 9769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown int mCurrentUserId = -1; 9869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown IMediaRouterClient mClient; 9969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown MediaRouterClientState mClientState; 10069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 101705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell final IAudioRoutesObserver.Stub mAudioRoutesObserver = new IAudioRoutesObserver.Stub() { 10266f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown @Override 103632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn public void dispatchAudioRoutesChanged(final AudioRoutesInfo newRoutes) { 104632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn mHandler.post(new Runnable() { 105632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn @Override public void run() { 106705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell updateAudioRoutes(newRoutes); 107632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } 108632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn }); 109632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } 110632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn }; 111632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn 112b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn Static(Context appContext) { 11369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mAppContext = appContext; 114b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn mResources = Resources.getSystem(); 115b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn mHandler = new Handler(appContext.getMainLooper()); 1169a1de308cea2d160778fd977825f10a07b49d738Adam Powell 117632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn IBinder b = ServiceManager.getService(Context.AUDIO_SERVICE); 118632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn mAudioService = IAudioService.Stub.asInterface(b); 1199a1de308cea2d160778fd977825f10a07b49d738Adam Powell 120705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell mDisplayService = (DisplayManager) appContext.getSystemService(Context.DISPLAY_SERVICE); 121705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 12269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mMediaRouterService = IMediaRouterService.Stub.asInterface( 12369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown ServiceManager.getService(Context.MEDIA_ROUTER_SERVICE)); 12469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 125dd0a19266d5c837069da1ea188744d54c8d723a8Adam Powell mSystemCategory = new RouteCategory( 126dd0a19266d5c837069da1ea188744d54c8d723a8Adam Powell com.android.internal.R.string.default_audio_route_category_name, 127705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell ROUTE_TYPE_LIVE_AUDIO | ROUTE_TYPE_LIVE_VIDEO, false); 128705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell mSystemCategory.mIsSystem = true; 129af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown 130af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown // Only the system can configure wifi displays. The display manager 131af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown // enforces this with a permission check. Set a flag here so that we 132af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown // know whether this process is actually allowed to scan and connect. 133af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown mCanConfigureWifiDisplays = appContext.checkPermission( 134af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown Manifest.permission.CONFIGURE_WIFI_DISPLAY, 135af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown Process.myPid(), Process.myUid()) == PackageManager.PERMISSION_GRANTED; 136b35c445f34e1a18e17aef3e3dfbc1c39b4d1815cAdam Powell } 137b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn 138b35c445f34e1a18e17aef3e3dfbc1c39b4d1815cAdam Powell // Called after sStatic is initialized 1398e37a85bf3dc39519942698dc90a3951306b934bAdam Powell void startMonitoringRoutes(Context appContext) { 140705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell mDefaultAudioVideo = new RouteInfo(mSystemCategory); 141705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell mDefaultAudioVideo.mNameResId = com.android.internal.R.string.default_audio_route_name; 142705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell mDefaultAudioVideo.mSupportedTypes = ROUTE_TYPE_LIVE_AUDIO | ROUTE_TYPE_LIVE_VIDEO; 1435830b0b33618940d65197cec99d697b21908fec8Chong Zhang mDefaultAudioVideo.updatePresentationDisplay(); 1442ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell addRouteStatic(mDefaultAudioVideo); 145632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn 1462ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell // This will select the active wifi display route if there is one. 1472ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell updateWifiDisplayStatus(mDisplayService.getWifiDisplayStatus()); 1482ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell 1492ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell appContext.registerReceiver(new WifiDisplayStatusChangedReceiver(), 1502ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell new IntentFilter(DisplayManager.ACTION_WIFI_DISPLAY_STATUS_CHANGED)); 1518e37a85bf3dc39519942698dc90a3951306b934bAdam Powell appContext.registerReceiver(new VolumeChangeReceiver(), 1528e37a85bf3dc39519942698dc90a3951306b934bAdam Powell new IntentFilter(AudioManager.VOLUME_CHANGED_ACTION)); 1538e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 15492130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown mDisplayService.registerDisplayListener(this, mHandler); 15592130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown 156705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell AudioRoutesInfo newAudioRoutes = null; 157632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn try { 158705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell newAudioRoutes = mAudioService.startWatchingRoutes(mAudioRoutesObserver); 159632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } catch (RemoteException e) { 160632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } 161705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell if (newAudioRoutes != null) { 1622ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell // This will select the active BT route if there is one and the current 1632ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell // selected route is the default system route, or if there is no selected 1642ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell // route yet. 165705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell updateAudioRoutes(newAudioRoutes); 166632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } 167705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 16869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Bind to the media router service. 16969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown rebindAsUser(UserHandle.myUserId()); 17069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 1712ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell // Select the default route if the above didn't sync us up 1722ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell // appropriately with relevant system state. 1732ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell if (mSelectedRoute == null) { 17469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown selectDefaultRouteStatic(); 1752ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell } 176632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } 177632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn 178705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell void updateAudioRoutes(AudioRoutesInfo newRoutes) { 17918687b7a275b3782e63d52cdbe8ee9df191046e7Jae Seo Log.v(TAG, "Updating audio routes: " + newRoutes); 1806156017c2217d0fbbbb03434986250ec6bbd69d8John Spurlock if (newRoutes.mainType != mCurAudioRoutesInfo.mainType) { 1816156017c2217d0fbbbb03434986250ec6bbd69d8John Spurlock mCurAudioRoutesInfo.mainType = newRoutes.mainType; 182632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn int name; 1836156017c2217d0fbbbb03434986250ec6bbd69d8John Spurlock if ((newRoutes.mainType&AudioRoutesInfo.MAIN_HEADPHONES) != 0 1846156017c2217d0fbbbb03434986250ec6bbd69d8John Spurlock || (newRoutes.mainType&AudioRoutesInfo.MAIN_HEADSET) != 0) { 185632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn name = com.android.internal.R.string.default_audio_route_name_headphones; 1866156017c2217d0fbbbb03434986250ec6bbd69d8John Spurlock } else if ((newRoutes.mainType&AudioRoutesInfo.MAIN_DOCK_SPEAKERS) != 0) { 187632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn name = com.android.internal.R.string.default_audio_route_name_dock_speakers; 1886156017c2217d0fbbbb03434986250ec6bbd69d8John Spurlock } else if ((newRoutes.mainType&AudioRoutesInfo.MAIN_HDMI) != 0) { 1894131a37366d59b5e61f55c4e48d2b22ee0c4cad4Adam Powell name = com.android.internal.R.string.default_media_route_name_hdmi; 190632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } else { 191632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn name = com.android.internal.R.string.default_audio_route_name; 192632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } 193705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell sStatic.mDefaultAudioVideo.mNameResId = name; 194705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell dispatchRouteChanged(sStatic.mDefaultAudioVideo); 195632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } 196bcf21e913af7252fb1994e07b6cf179321ecd049Adam Powell 1976156017c2217d0fbbbb03434986250ec6bbd69d8John Spurlock final int mainType = mCurAudioRoutesInfo.mainType; 1983f369684e13dfea0ba8ea134f3e95930b0dd7df0Adam Powell 1996156017c2217d0fbbbb03434986250ec6bbd69d8John Spurlock if (!TextUtils.equals(newRoutes.bluetoothName, mCurAudioRoutesInfo.bluetoothName)) { 2006156017c2217d0fbbbb03434986250ec6bbd69d8John Spurlock mCurAudioRoutesInfo.bluetoothName = newRoutes.bluetoothName; 2016156017c2217d0fbbbb03434986250ec6bbd69d8John Spurlock if (mCurAudioRoutesInfo.bluetoothName != null) { 202632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn if (sStatic.mBluetoothA2dpRoute == null) { 203632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn final RouteInfo info = new RouteInfo(sStatic.mSystemCategory); 2046156017c2217d0fbbbb03434986250ec6bbd69d8John Spurlock info.mName = mCurAudioRoutesInfo.bluetoothName; 20556d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown info.mDescription = sStatic.mResources.getText( 20656d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown com.android.internal.R.string.bluetooth_a2dp_audio_route_name); 207632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn info.mSupportedTypes = ROUTE_TYPE_LIVE_AUDIO; 2089dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang info.mDeviceType = RouteInfo.DEVICE_TYPE_BLUETOOTH; 209632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn sStatic.mBluetoothA2dpRoute = info; 2102ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell addRouteStatic(sStatic.mBluetoothA2dpRoute); 211632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } else { 2126156017c2217d0fbbbb03434986250ec6bbd69d8John Spurlock sStatic.mBluetoothA2dpRoute.mName = mCurAudioRoutesInfo.bluetoothName; 213632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn dispatchRouteChanged(sStatic.mBluetoothA2dpRoute); 214632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } 215632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } else if (sStatic.mBluetoothA2dpRoute != null) { 21669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown removeRouteStatic(sStatic.mBluetoothA2dpRoute); 217632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn sStatic.mBluetoothA2dpRoute = null; 218632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } 219632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } 220bcf21e913af7252fb1994e07b6cf179321ecd049Adam Powell 221bcf21e913af7252fb1994e07b6cf179321ecd049Adam Powell if (mBluetoothA2dpRoute != null) { 222fa6f70e225a7370c1ecb21ee7076c9086ecb9e9aSungsoo final boolean a2dpEnabled = isBluetoothA2dpOn(); 223fa6f70e225a7370c1ecb21ee7076c9086ecb9e9aSungsoo if (mainType != AudioRoutesInfo.MAIN_SPEAKER && 224fa6f70e225a7370c1ecb21ee7076c9086ecb9e9aSungsoo mSelectedRoute == mBluetoothA2dpRoute && !a2dpEnabled) { 225fa6f70e225a7370c1ecb21ee7076c9086ecb9e9aSungsoo selectRouteStatic(ROUTE_TYPE_LIVE_AUDIO, mDefaultAudioVideo, false); 226fa6f70e225a7370c1ecb21ee7076c9086ecb9e9aSungsoo } else if ((mSelectedRoute == mDefaultAudioVideo || mSelectedRoute == null) && 227fa6f70e225a7370c1ecb21ee7076c9086ecb9e9aSungsoo a2dpEnabled) { 22869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown selectRouteStatic(ROUTE_TYPE_LIVE_AUDIO, mBluetoothA2dpRoute, false); 229bcf21e913af7252fb1994e07b6cf179321ecd049Adam Powell } 230bcf21e913af7252fb1994e07b6cf179321ecd049Adam Powell } 231b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn } 23292130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown 233fa6f70e225a7370c1ecb21ee7076c9086ecb9e9aSungsoo boolean isBluetoothA2dpOn() { 234fa6f70e225a7370c1ecb21ee7076c9086ecb9e9aSungsoo try { 235fa6f70e225a7370c1ecb21ee7076c9086ecb9e9aSungsoo return mAudioService.isBluetoothA2dpOn(); 236fa6f70e225a7370c1ecb21ee7076c9086ecb9e9aSungsoo } catch (RemoteException e) { 237fa6f70e225a7370c1ecb21ee7076c9086ecb9e9aSungsoo Log.e(TAG, "Error querying Bluetooth A2DP state", e); 238fa6f70e225a7370c1ecb21ee7076c9086ecb9e9aSungsoo return false; 239fa6f70e225a7370c1ecb21ee7076c9086ecb9e9aSungsoo } 240fa6f70e225a7370c1ecb21ee7076c9086ecb9e9aSungsoo } 241fa6f70e225a7370c1ecb21ee7076c9086ecb9e9aSungsoo 24269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown void updateDiscoveryRequest() { 24369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // What are we looking for today? 24469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown int routeTypes = 0; 24569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown int passiveRouteTypes = 0; 24669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown boolean activeScan = false; 24769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown boolean activeScanWifiDisplay = false; 24869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final int count = mCallbacks.size(); 24969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown for (int i = 0; i < count; i++) { 25069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown CallbackInfo cbi = mCallbacks.get(i); 25169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if ((cbi.flags & (CALLBACK_FLAG_PERFORM_ACTIVE_SCAN 25269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown | CALLBACK_FLAG_REQUEST_DISCOVERY)) != 0) { 25369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Discovery explicitly requested. 25469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown routeTypes |= cbi.type; 25569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } else if ((cbi.flags & CALLBACK_FLAG_PASSIVE_DISCOVERY) != 0) { 25669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Discovery only passively requested. 25769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown passiveRouteTypes |= cbi.type; 25869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } else { 25969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Legacy case since applications don't specify the discovery flag. 26069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Unfortunately we just have to assume they always need discovery 26169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // whenever they have a callback registered. 26269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown routeTypes |= cbi.type; 26369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 26469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if ((cbi.flags & CALLBACK_FLAG_PERFORM_ACTIVE_SCAN) != 0) { 26569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown activeScan = true; 266af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown if ((cbi.type & ROUTE_TYPE_REMOTE_DISPLAY) != 0) { 26769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown activeScanWifiDisplay = true; 26869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 26969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 27069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 27169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (routeTypes != 0 || activeScan) { 27269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // If someone else requests discovery then enable the passive listeners. 27369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // This is used by the MediaRouteButton and MediaRouteActionProvider since 27469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // they don't receive lifecycle callbacks from the Activity. 27569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown routeTypes |= passiveRouteTypes; 27669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 27769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 27869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Update wifi display scanning. 279ce468a35b388ca46578934706b38dbae94941643Jeff Brown // TODO: All of this should be managed by the media router service. 280ce468a35b388ca46578934706b38dbae94941643Jeff Brown if (mCanConfigureWifiDisplays) { 281ce468a35b388ca46578934706b38dbae94941643Jeff Brown if (mSelectedRoute != null 282ce468a35b388ca46578934706b38dbae94941643Jeff Brown && mSelectedRoute.matchesTypes(ROUTE_TYPE_REMOTE_DISPLAY)) { 283ce468a35b388ca46578934706b38dbae94941643Jeff Brown // Don't scan while already connected to a remote display since 284ce468a35b388ca46578934706b38dbae94941643Jeff Brown // it may interfere with the ongoing transmission. 285ce468a35b388ca46578934706b38dbae94941643Jeff Brown activeScanWifiDisplay = false; 28666f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown } 287ce468a35b388ca46578934706b38dbae94941643Jeff Brown if (activeScanWifiDisplay) { 288ce468a35b388ca46578934706b38dbae94941643Jeff Brown if (!mActivelyScanningWifiDisplays) { 289ce468a35b388ca46578934706b38dbae94941643Jeff Brown mActivelyScanningWifiDisplays = true; 290ce468a35b388ca46578934706b38dbae94941643Jeff Brown mDisplayService.startWifiDisplayScan(); 291ce468a35b388ca46578934706b38dbae94941643Jeff Brown } 292ce468a35b388ca46578934706b38dbae94941643Jeff Brown } else { 293ce468a35b388ca46578934706b38dbae94941643Jeff Brown if (mActivelyScanningWifiDisplays) { 294ce468a35b388ca46578934706b38dbae94941643Jeff Brown mActivelyScanningWifiDisplays = false; 295ce468a35b388ca46578934706b38dbae94941643Jeff Brown mDisplayService.stopWifiDisplayScan(); 296ce468a35b388ca46578934706b38dbae94941643Jeff Brown } 29766f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown } 29866f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown } 29966f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown 30069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Tell the media router service all about it. 30169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (routeTypes != mDiscoveryRequestRouteTypes 30269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown || activeScan != mDiscoverRequestActiveScan) { 30369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mDiscoveryRequestRouteTypes = routeTypes; 30469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mDiscoverRequestActiveScan = activeScan; 30569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown publishClientDiscoveryRequest(); 30666f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown } 30766f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown } 30866f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown 30992130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown @Override 31092130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown public void onDisplayAdded(int displayId) { 31192130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown updatePresentationDisplays(displayId); 31292130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown } 31392130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown 31492130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown @Override 31592130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown public void onDisplayChanged(int displayId) { 31692130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown updatePresentationDisplays(displayId); 31792130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown } 31892130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown 31992130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown @Override 32092130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown public void onDisplayRemoved(int displayId) { 32192130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown updatePresentationDisplays(displayId); 32292130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown } 32392130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown 32492130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown public Display[] getAllPresentationDisplays() { 32592130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown return mDisplayService.getDisplays(DisplayManager.DISPLAY_CATEGORY_PRESENTATION); 32692130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown } 32792130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown 32892130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown private void updatePresentationDisplays(int changedDisplayId) { 32992130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown final int count = mRoutes.size(); 33092130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown for (int i = 0; i < count; i++) { 3315830b0b33618940d65197cec99d697b21908fec8Chong Zhang final RouteInfo route = mRoutes.get(i); 3325830b0b33618940d65197cec99d697b21908fec8Chong Zhang if (route.updatePresentationDisplay() || (route.mPresentationDisplay != null 3335830b0b33618940d65197cec99d697b21908fec8Chong Zhang && route.mPresentationDisplay.getDisplayId() == changedDisplayId)) { 3345830b0b33618940d65197cec99d697b21908fec8Chong Zhang dispatchRoutePresentationDisplayChanged(route); 33592130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown } 33692130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown } 33792130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown } 33869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 33969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown void setSelectedRoute(RouteInfo info, boolean explicit) { 34069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Must be non-reentrant. 34169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mSelectedRoute = info; 34269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown publishClientSelectedRoute(explicit); 34369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 34469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 34569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown void rebindAsUser(int userId) { 34669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (mCurrentUserId != userId || userId < 0 || mClient == null) { 34769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (mClient != null) { 34869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown try { 34969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mMediaRouterService.unregisterClient(mClient); 35069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } catch (RemoteException ex) { 35169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Log.e(TAG, "Unable to unregister media router client.", ex); 35269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 35369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mClient = null; 35469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 35569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 35669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mCurrentUserId = userId; 35769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 35869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown try { 35969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Client client = new Client(); 36069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mMediaRouterService.registerClientAsUser(client, 36169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mAppContext.getPackageName(), userId); 36269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mClient = client; 36369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } catch (RemoteException ex) { 36469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Log.e(TAG, "Unable to register media router client.", ex); 36569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 36669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 36769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown publishClientDiscoveryRequest(); 36869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown publishClientSelectedRoute(false); 36969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown updateClientState(); 37069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 37169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 37269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 37369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown void publishClientDiscoveryRequest() { 37469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (mClient != null) { 37569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown try { 37669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mMediaRouterService.setDiscoveryRequest(mClient, 37769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mDiscoveryRequestRouteTypes, mDiscoverRequestActiveScan); 37869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } catch (RemoteException ex) { 37969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Log.e(TAG, "Unable to publish media router client discovery request.", ex); 38069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 38169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 38269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 38369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 38469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown void publishClientSelectedRoute(boolean explicit) { 38569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (mClient != null) { 38669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown try { 38769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mMediaRouterService.setSelectedRoute(mClient, 38869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mSelectedRoute != null ? mSelectedRoute.mGlobalRouteId : null, 38969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown explicit); 39069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } catch (RemoteException ex) { 39169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Log.e(TAG, "Unable to publish media router client selected route.", ex); 39269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 39369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 39469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 39569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 39669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown void updateClientState() { 39769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Update the client state. 39869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mClientState = null; 39969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (mClient != null) { 40069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown try { 40169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mClientState = mMediaRouterService.getState(mClient); 40269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } catch (RemoteException ex) { 40369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Log.e(TAG, "Unable to retrieve media router client state.", ex); 40469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 40569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 40669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final ArrayList<MediaRouterClientState.RouteInfo> globalRoutes = 40769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mClientState != null ? mClientState.routes : null; 40869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final String globallySelectedRouteId = mClientState != null ? 40969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mClientState.globallySelectedRouteId : null; 41069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 41169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Add or update routes. 41269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final int globalRouteCount = globalRoutes != null ? globalRoutes.size() : 0; 41369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown for (int i = 0; i < globalRouteCount; i++) { 41469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final MediaRouterClientState.RouteInfo globalRoute = globalRoutes.get(i); 41569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown RouteInfo route = findGlobalRoute(globalRoute.id); 41669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (route == null) { 41769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route = makeGlobalRoute(globalRoute); 41869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown addRouteStatic(route); 41969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } else { 42069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown updateGlobalRoute(route, globalRoute); 42169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 42269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 42369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 42469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Synchronize state with the globally selected route. 42569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (globallySelectedRouteId != null) { 42669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final RouteInfo route = findGlobalRoute(globallySelectedRouteId); 42769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (route == null) { 42869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Log.w(TAG, "Could not find new globally selected route: " 42969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown + globallySelectedRouteId); 43069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } else if (route != mSelectedRoute) { 43169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (DEBUG) { 43269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Log.d(TAG, "Selecting new globally selected route: " + route); 43369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 43469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown selectRouteStatic(route.mSupportedTypes, route, false); 43569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 43669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } else if (mSelectedRoute != null && mSelectedRoute.mGlobalRouteId != null) { 43769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (DEBUG) { 43869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Log.d(TAG, "Unselecting previous globally selected route: " + mSelectedRoute); 43969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 44069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown selectDefaultRouteStatic(); 44169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 44269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 44369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Remove defunct routes. 44469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown outer: for (int i = mRoutes.size(); i-- > 0; ) { 44569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final RouteInfo route = mRoutes.get(i); 44669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final String globalRouteId = route.mGlobalRouteId; 44769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (globalRouteId != null) { 44869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown for (int j = 0; j < globalRouteCount; j++) { 44969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown MediaRouterClientState.RouteInfo globalRoute = globalRoutes.get(j); 45069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (globalRouteId.equals(globalRoute.id)) { 45169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown continue outer; // found 45269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 45369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 45469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // not found 45569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown removeRouteStatic(route); 45669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 45769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 45869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 45969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 46069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown void requestSetVolume(RouteInfo route, int volume) { 46169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (route.mGlobalRouteId != null && mClient != null) { 46269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown try { 46369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mMediaRouterService.requestSetVolume(mClient, 46469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mGlobalRouteId, volume); 46569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } catch (RemoteException ex) { 46669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Log.w(TAG, "Unable to request volume change.", ex); 46769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 46869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 46969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 47069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 47169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown void requestUpdateVolume(RouteInfo route, int direction) { 47269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (route.mGlobalRouteId != null && mClient != null) { 47369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown try { 47469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mMediaRouterService.requestUpdateVolume(mClient, 47569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mGlobalRouteId, direction); 47669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } catch (RemoteException ex) { 47769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Log.w(TAG, "Unable to request volume change.", ex); 47869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 47969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 48069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 48169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 48269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown RouteInfo makeGlobalRoute(MediaRouterClientState.RouteInfo globalRoute) { 48369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown RouteInfo route = new RouteInfo(sStatic.mSystemCategory); 48469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mGlobalRouteId = globalRoute.id; 48569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mName = globalRoute.name; 48669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mDescription = globalRoute.description; 48769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mSupportedTypes = globalRoute.supportedTypes; 4889dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang route.mDeviceType = globalRoute.deviceType; 48969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mEnabled = globalRoute.enabled; 49039ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown route.setRealStatusCode(globalRoute.statusCode); 49169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mPlaybackType = globalRoute.playbackType; 49269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mPlaybackStream = globalRoute.playbackStream; 49369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mVolume = globalRoute.volume; 49469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mVolumeMax = globalRoute.volumeMax; 49569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mVolumeHandling = globalRoute.volumeHandling; 4965830b0b33618940d65197cec99d697b21908fec8Chong Zhang route.mPresentationDisplayId = globalRoute.presentationDisplayId; 4975830b0b33618940d65197cec99d697b21908fec8Chong Zhang route.updatePresentationDisplay(); 49869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return route; 49969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 50069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 50169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown void updateGlobalRoute(RouteInfo route, MediaRouterClientState.RouteInfo globalRoute) { 50269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown boolean changed = false; 50369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown boolean volumeChanged = false; 50469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown boolean presentationDisplayChanged = false; 50569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 506e6585b32ea586743258a5457e2184ffc087f2d2fKenny Root if (!Objects.equals(route.mName, globalRoute.name)) { 50769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mName = globalRoute.name; 50869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown changed = true; 50969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 510e6585b32ea586743258a5457e2184ffc087f2d2fKenny Root if (!Objects.equals(route.mDescription, globalRoute.description)) { 51169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mDescription = globalRoute.description; 51269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown changed = true; 51369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 514af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown final int oldSupportedTypes = route.mSupportedTypes; 515af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown if (oldSupportedTypes != globalRoute.supportedTypes) { 51669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mSupportedTypes = globalRoute.supportedTypes; 51769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown changed = true; 51869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 51969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (route.mEnabled != globalRoute.enabled) { 52069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mEnabled = globalRoute.enabled; 52169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown changed = true; 52269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 52339ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown if (route.mRealStatusCode != globalRoute.statusCode) { 52439ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown route.setRealStatusCode(globalRoute.statusCode); 52569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown changed = true; 52669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 52769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (route.mPlaybackType != globalRoute.playbackType) { 52869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mPlaybackType = globalRoute.playbackType; 52969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown changed = true; 53069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 53169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (route.mPlaybackStream != globalRoute.playbackStream) { 53269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mPlaybackStream = globalRoute.playbackStream; 53369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown changed = true; 53469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 53569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (route.mVolume != globalRoute.volume) { 53669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mVolume = globalRoute.volume; 53769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown changed = true; 53869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown volumeChanged = true; 53969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 54069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (route.mVolumeMax != globalRoute.volumeMax) { 54169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mVolumeMax = globalRoute.volumeMax; 54269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown changed = true; 54369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown volumeChanged = true; 54469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 54569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (route.mVolumeHandling != globalRoute.volumeHandling) { 54669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mVolumeHandling = globalRoute.volumeHandling; 54769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown changed = true; 54869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown volumeChanged = true; 54969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 5505830b0b33618940d65197cec99d697b21908fec8Chong Zhang if (route.mPresentationDisplayId != globalRoute.presentationDisplayId) { 5515830b0b33618940d65197cec99d697b21908fec8Chong Zhang route.mPresentationDisplayId = globalRoute.presentationDisplayId; 5525830b0b33618940d65197cec99d697b21908fec8Chong Zhang route.updatePresentationDisplay(); 55369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown changed = true; 55469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown presentationDisplayChanged = true; 55569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 55669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 55769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (changed) { 558af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown dispatchRouteChanged(route, oldSupportedTypes); 55969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 56069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (volumeChanged) { 56169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown dispatchRouteVolumeChanged(route); 56269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 56369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (presentationDisplayChanged) { 56469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown dispatchRoutePresentationDisplayChanged(route); 56569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 56669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 56769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 56869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown RouteInfo findGlobalRoute(String globalRouteId) { 56969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final int count = mRoutes.size(); 57069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown for (int i = 0; i < count; i++) { 57169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final RouteInfo route = mRoutes.get(i); 57269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (globalRouteId.equals(route.mGlobalRouteId)) { 57369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return route; 57469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 57569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 57669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return null; 57769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 57869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 57969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final class Client extends IMediaRouterClient.Stub { 58069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown @Override 58169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public void onStateChanged() { 58269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mHandler.post(new Runnable() { 58369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown @Override 58469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public void run() { 58569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (Client.this == mClient) { 58669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown updateClientState(); 58769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 58869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 58969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown }); 59069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 59169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 592b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn } 5939a1de308cea2d160778fd977825f10a07b49d738Adam Powell 594b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn static Static sStatic; 5959a1de308cea2d160778fd977825f10a07b49d738Adam Powell 5969a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 5979a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Route type flag for live audio. 5989a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 5999a1de308cea2d160778fd977825f10a07b49d738Adam Powell * <p>A device that supports live audio routing will allow the media audio stream 6009a1de308cea2d160778fd977825f10a07b49d738Adam Powell * to be routed to supported destinations. This can include internal speakers or 6019a1de308cea2d160778fd977825f10a07b49d738Adam Powell * audio jacks on the device itself, A2DP devices, and more.</p> 6029a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 6039a1de308cea2d160778fd977825f10a07b49d738Adam Powell * <p>Once initiated this routing is transparent to the application. All audio 6049a1de308cea2d160778fd977825f10a07b49d738Adam Powell * played on the media stream will be routed to the selected destination.</p> 6059a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 60669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public static final int ROUTE_TYPE_LIVE_AUDIO = 1 << 0; 6079a1de308cea2d160778fd977825f10a07b49d738Adam Powell 6089a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 609705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell * Route type flag for live video. 610705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell * 611705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell * <p>A device that supports live video routing will allow a mirrored version 612705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell * of the device's primary display or a customized 613705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell * {@link android.app.Presentation Presentation} to be routed to supported destinations.</p> 614705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell * 615705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell * <p>Once initiated, display mirroring is transparent to the application. 616705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell * While remote routing is active the application may use a 617705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell * {@link android.app.Presentation Presentation} to replace the mirrored view 618705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell * on the external display with different content.</p> 61992130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * 62092130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * @see RouteInfo#getPresentationDisplay() 62192130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * @see android.app.Presentation 622705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell */ 62369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public static final int ROUTE_TYPE_LIVE_VIDEO = 1 << 1; 62469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 62569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown /** 62669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * Temporary interop constant to identify remote displays. 62769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * @hide To be removed when media router API is updated. 62869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown */ 62969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public static final int ROUTE_TYPE_REMOTE_DISPLAY = 1 << 2; 630705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 631705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell /** 6329a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Route type flag for application-specific usage. 6339a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 6349a1de308cea2d160778fd977825f10a07b49d738Adam Powell * <p>Unlike other media route types, user routes are managed by the application. 6359a1de308cea2d160778fd977825f10a07b49d738Adam Powell * The MediaRouter will manage and dispatch events for user routes, but the application 6369a1de308cea2d160778fd977825f10a07b49d738Adam Powell * is expected to interpret the meaning of these events and perform the requested 6379a1de308cea2d160778fd977825f10a07b49d738Adam Powell * routing tasks.</p> 6389a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 63969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public static final int ROUTE_TYPE_USER = 1 << 23; 64069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 64169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown static final int ROUTE_TYPE_ANY = ROUTE_TYPE_LIVE_AUDIO | ROUTE_TYPE_LIVE_VIDEO 64269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown | ROUTE_TYPE_REMOTE_DISPLAY | ROUTE_TYPE_USER; 6439a1de308cea2d160778fd977825f10a07b49d738Adam Powell 64466f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown /** 64566f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * Flag for {@link #addCallback}: Actively scan for routes while this callback 64666f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * is registered. 64766f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * <p> 64866f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * When this flag is specified, the media router will actively scan for new 64966f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * routes. Certain routes, such as wifi display routes, may not be discoverable 65066f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * except when actively scanning. This flag is typically used when the route picker 65166f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * dialog has been opened by the user to ensure that the route information is 65266f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * up to date. 65366f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * </p><p> 65466f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * Active scanning may consume a significant amount of power and may have intrusive 65566f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * effects on wireless connectivity. Therefore it is important that active scanning 65666f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * only be requested when it is actually needed to satisfy a user request to 65766f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * discover and select a new route. 65866f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * </p> 65966f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown */ 66014507e257af5d71577574e25cbd690c4b54c9272Jeff Brown public static final int CALLBACK_FLAG_PERFORM_ACTIVE_SCAN = 1 << 0; 66166f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown 66266f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown /** 66366f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * Flag for {@link #addCallback}: Do not filter route events. 66466f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * <p> 66566f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * When this flag is specified, the callback will be invoked for event that affect any 66669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * route even if they do not match the callback's filter. 66766f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * </p> 66866f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown */ 66966f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown public static final int CALLBACK_FLAG_UNFILTERED_EVENTS = 1 << 1; 67066f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown 67169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown /** 67269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * Explicitly requests discovery. 67369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * 67469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * @hide Future API ported from support library. Revisit this later. 67569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown */ 67669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public static final int CALLBACK_FLAG_REQUEST_DISCOVERY = 1 << 2; 67769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 67869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown /** 67969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * Requests that discovery be performed but only if there is some other active 68069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * callback already registered. 68169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * 68269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * @hide Compatibility workaround for the fact that applications do not currently 68369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * request discovery explicitly (except when using the support library API). 68469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown */ 68569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public static final int CALLBACK_FLAG_PASSIVE_DISCOVERY = 1 << 3; 68669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 6870abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown /** 6880abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * Flag for {@link #isRouteAvailable}: Ignore the default route. 6890abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * <p> 6900abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * This flag is used to determine whether a matching non-default route is available. 6910abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * This constraint may be used to decide whether to offer the route chooser dialog 6920abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * to the user. There is no point offering the chooser if there are no 6930abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * non-default choices. 6940abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * </p> 6950abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * 6960abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * @hide Future API ported from support library. Revisit this later. 6970abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown */ 6980abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown public static final int AVAILABILITY_FLAG_IGNORE_DEFAULT_ROUTE = 1 << 0; 6990abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown 7009a1de308cea2d160778fd977825f10a07b49d738Adam Powell // Maps application contexts 7019a1de308cea2d160778fd977825f10a07b49d738Adam Powell static final HashMap<Context, MediaRouter> sRouters = new HashMap<Context, MediaRouter>(); 7029a1de308cea2d160778fd977825f10a07b49d738Adam Powell 7039a1de308cea2d160778fd977825f10a07b49d738Adam Powell static String typesToString(int types) { 7049a1de308cea2d160778fd977825f10a07b49d738Adam Powell final StringBuilder result = new StringBuilder(); 7059a1de308cea2d160778fd977825f10a07b49d738Adam Powell if ((types & ROUTE_TYPE_LIVE_AUDIO) != 0) { 7069a1de308cea2d160778fd977825f10a07b49d738Adam Powell result.append("ROUTE_TYPE_LIVE_AUDIO "); 7079a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 7082bb7c122ef6ce8539dfbaeb3292adcd942185f82Bryan Mawhinney if ((types & ROUTE_TYPE_LIVE_VIDEO) != 0) { 7092bb7c122ef6ce8539dfbaeb3292adcd942185f82Bryan Mawhinney result.append("ROUTE_TYPE_LIVE_VIDEO "); 7102bb7c122ef6ce8539dfbaeb3292adcd942185f82Bryan Mawhinney } 71169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if ((types & ROUTE_TYPE_REMOTE_DISPLAY) != 0) { 71269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown result.append("ROUTE_TYPE_REMOTE_DISPLAY "); 71369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 7149a1de308cea2d160778fd977825f10a07b49d738Adam Powell if ((types & ROUTE_TYPE_USER) != 0) { 7159a1de308cea2d160778fd977825f10a07b49d738Adam Powell result.append("ROUTE_TYPE_USER "); 7169a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 7179a1de308cea2d160778fd977825f10a07b49d738Adam Powell return result.toString(); 7189a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 7199a1de308cea2d160778fd977825f10a07b49d738Adam Powell 720b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn /** @hide */ 721b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn public MediaRouter(Context context) { 722b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn synchronized (Static.class) { 723b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn if (sStatic == null) { 7248e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final Context appContext = context.getApplicationContext(); 7258e37a85bf3dc39519942698dc90a3951306b934bAdam Powell sStatic = new Static(appContext); 7268e37a85bf3dc39519942698dc90a3951306b934bAdam Powell sStatic.startMonitoringRoutes(appContext); 727b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn } 7289a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 7299a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 7309a1de308cea2d160778fd977825f10a07b49d738Adam Powell 731690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell /** 7323afc18af2cea898753b10e8575dcf20c11356bcaJeff Brown * Gets the default route for playing media content on the system. 7333afc18af2cea898753b10e8575dcf20c11356bcaJeff Brown * <p> 7343afc18af2cea898753b10e8575dcf20c11356bcaJeff Brown * The system always provides a default route. 7353afc18af2cea898753b10e8575dcf20c11356bcaJeff Brown * </p> 7363afc18af2cea898753b10e8575dcf20c11356bcaJeff Brown * 7373afc18af2cea898753b10e8575dcf20c11356bcaJeff Brown * @return The default route, which is guaranteed to never be null. 738690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell */ 7393afc18af2cea898753b10e8575dcf20c11356bcaJeff Brown public RouteInfo getDefaultRoute() { 740705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell return sStatic.mDefaultAudioVideo; 741690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell } 742690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell 743690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell /** 7444599696591f745b3a546197d2ba7e5cfc5562484Adam Powell * @hide for use by framework routing UI 7454599696591f745b3a546197d2ba7e5cfc5562484Adam Powell */ 7463afc18af2cea898753b10e8575dcf20c11356bcaJeff Brown public RouteCategory getSystemCategory() { 7474599696591f745b3a546197d2ba7e5cfc5562484Adam Powell return sStatic.mSystemCategory; 7484599696591f745b3a546197d2ba7e5cfc5562484Adam Powell } 7494599696591f745b3a546197d2ba7e5cfc5562484Adam Powell 7500abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown /** @hide */ 7510abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown public RouteInfo getSelectedRoute() { 7520abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown return getSelectedRoute(ROUTE_TYPE_ANY); 7530abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown } 7540abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown 7554599696591f745b3a546197d2ba7e5cfc5562484Adam Powell /** 7561cf2ca83584a4cf0aa3ded787bd191b9a60e3521Adam Powell * Return the currently selected route for any of the given types 757690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell * 758690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell * @param type route types 759690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell * @return the selected route 760690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell */ 761690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell public RouteInfo getSelectedRoute(int type) { 7621cf2ca83584a4cf0aa3ded787bd191b9a60e3521Adam Powell if (sStatic.mSelectedRoute != null && 7631cf2ca83584a4cf0aa3ded787bd191b9a60e3521Adam Powell (sStatic.mSelectedRoute.mSupportedTypes & type) != 0) { 7641cf2ca83584a4cf0aa3ded787bd191b9a60e3521Adam Powell // If the selected route supports any of the types supplied, it's still considered 7651cf2ca83584a4cf0aa3ded787bd191b9a60e3521Adam Powell // 'selected' for that type. 7661cf2ca83584a4cf0aa3ded787bd191b9a60e3521Adam Powell return sStatic.mSelectedRoute; 7671cf2ca83584a4cf0aa3ded787bd191b9a60e3521Adam Powell } else if (type == ROUTE_TYPE_USER) { 7681cf2ca83584a4cf0aa3ded787bd191b9a60e3521Adam Powell // The caller specifically asked for a user route and the currently selected route 7691cf2ca83584a4cf0aa3ded787bd191b9a60e3521Adam Powell // doesn't qualify. 7701cf2ca83584a4cf0aa3ded787bd191b9a60e3521Adam Powell return null; 7711cf2ca83584a4cf0aa3ded787bd191b9a60e3521Adam Powell } 7721cf2ca83584a4cf0aa3ded787bd191b9a60e3521Adam Powell // If the above didn't match and we're not specifically asking for a user route, 7731cf2ca83584a4cf0aa3ded787bd191b9a60e3521Adam Powell // consider the default selected. 7741cf2ca83584a4cf0aa3ded787bd191b9a60e3521Adam Powell return sStatic.mDefaultAudioVideo; 775690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell } 776690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell 7779a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 7780abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * Returns true if there is a route that matches the specified types. 7790abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * <p> 7800abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * This method returns true if there are any available routes that match the types 7810abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * regardless of whether they are enabled or disabled. If the 7820abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * {@link #AVAILABILITY_FLAG_IGNORE_DEFAULT_ROUTE} flag is specified, then 7830abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * the method will only consider non-default routes. 7840abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * </p> 7850abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * 7860abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * @param types The types to match. 7870abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * @param flags Flags to control the determination of whether a route may be available. 7880abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * May be zero or {@link #AVAILABILITY_FLAG_IGNORE_DEFAULT_ROUTE}. 7890abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * @return True if a matching route may be available. 7900abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * 7910abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * @hide Future API ported from support library. Revisit this later. 7920abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown */ 7930abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown public boolean isRouteAvailable(int types, int flags) { 7940abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown final int count = sStatic.mRoutes.size(); 7950abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown for (int i = 0; i < count; i++) { 7960abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown RouteInfo route = sStatic.mRoutes.get(i); 7970abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown if (route.matchesTypes(types)) { 7980abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown if ((flags & AVAILABILITY_FLAG_IGNORE_DEFAULT_ROUTE) == 0 7990abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown || route != sStatic.mDefaultAudioVideo) { 8000abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown return true; 8010abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown } 8020abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown } 8030abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown } 8040abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown 8050abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown // It doesn't look like we can find a matching route right now. 8060abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown return false; 8070abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown } 8080abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown 8090abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown /** 8109a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Add a callback to listen to events about specific kinds of media routes. 8119a1de308cea2d160778fd977825f10a07b49d738Adam Powell * If the specified callback is already registered, its registration will be updated for any 8129a1de308cea2d160778fd977825f10a07b49d738Adam Powell * additional route types specified. 81366f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * <p> 81466f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * This is a convenience method that has the same effect as calling 81566f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * {@link #addCallback(int, Callback, int)} without flags. 81666f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * </p> 8179a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 8189a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param types Types of routes this callback is interested in 8199a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param cb Callback to add 8209a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 8219a1de308cea2d160778fd977825f10a07b49d738Adam Powell public void addCallback(int types, Callback cb) { 82266f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown addCallback(types, cb, 0); 82366f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown } 82466f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown 82566f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown /** 82666f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * Add a callback to listen to events about specific kinds of media routes. 82766f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * If the specified callback is already registered, its registration will be updated for any 82866f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * additional route types specified. 82966f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * <p> 83066f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * By default, the callback will only be invoked for events that affect routes 83166f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * that match the specified selector. The filtering may be disabled by specifying 83266f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * the {@link #CALLBACK_FLAG_UNFILTERED_EVENTS} flag. 83366f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * </p> 83466f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * 83566f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * @param types Types of routes this callback is interested in 83666f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * @param cb Callback to add 83766f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * @param flags Flags to control the behavior of the callback. 83814507e257af5d71577574e25cbd690c4b54c9272Jeff Brown * May be zero or a combination of {@link #CALLBACK_FLAG_PERFORM_ACTIVE_SCAN} and 83966f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * {@link #CALLBACK_FLAG_UNFILTERED_EVENTS}. 84066f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown */ 84166f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown public void addCallback(int types, Callback cb, int flags) { 84266f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown CallbackInfo info; 84366f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown int index = findCallbackInfo(cb); 84466f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown if (index >= 0) { 84566f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown info = sStatic.mCallbacks.get(index); 84666f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown info.type |= types; 84766f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown info.flags |= flags; 84866f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown } else { 84966f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown info = new CallbackInfo(cb, types, flags, this); 85066f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown sStatic.mCallbacks.add(info); 85166f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown } 85269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown sStatic.updateDiscoveryRequest(); 8539a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 8549a1de308cea2d160778fd977825f10a07b49d738Adam Powell 8559a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 8569a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Remove the specified callback. It will no longer receive events about media routing. 8579a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 8589a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param cb Callback to remove 8599a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 8609a1de308cea2d160778fd977825f10a07b49d738Adam Powell public void removeCallback(Callback cb) { 86166f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown int index = findCallbackInfo(cb); 86266f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown if (index >= 0) { 86369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown sStatic.mCallbacks.remove(index); 86469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown sStatic.updateDiscoveryRequest(); 86566f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown } else { 86666f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown Log.w(TAG, "removeCallback(" + cb + "): callback not registered"); 86766f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown } 86866f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown } 86966f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown 87066f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown private int findCallbackInfo(Callback cb) { 871b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn final int count = sStatic.mCallbacks.size(); 8729a1de308cea2d160778fd977825f10a07b49d738Adam Powell for (int i = 0; i < count; i++) { 87366f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown final CallbackInfo info = sStatic.mCallbacks.get(i); 87466f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown if (info.cb == cb) { 87566f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown return i; 8769a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 8779a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 87866f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown return -1; 8799a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 8809a1de308cea2d160778fd977825f10a07b49d738Adam Powell 881d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell /** 882d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * Select the specified route to use for output of the given media types. 8833afc18af2cea898753b10e8575dcf20c11356bcaJeff Brown * <p class="note"> 8843afc18af2cea898753b10e8575dcf20c11356bcaJeff Brown * As API version 18, this function may be used to select any route. 8853afc18af2cea898753b10e8575dcf20c11356bcaJeff Brown * In prior versions, this function could only be used to select user 8863afc18af2cea898753b10e8575dcf20c11356bcaJeff Brown * routes and would ignore any attempt to select a system route. 8873afc18af2cea898753b10e8575dcf20c11356bcaJeff Brown * </p> 888d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * 889d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param types type flags indicating which types this route should be used for. 890d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * The route must support at least a subset. 891d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param route Route to select 8929d93a378c5158d14f80d46af70433234330ec568P.Y. Laligand * @throws IllegalArgumentException if the given route is {@code null} 893d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell */ 8949d93a378c5158d14f80d46af70433234330ec568P.Y. Laligand public void selectRoute(int types, @NonNull RouteInfo route) { 8959d93a378c5158d14f80d46af70433234330ec568P.Y. Laligand if (route == null) { 8969d93a378c5158d14f80d46af70433234330ec568P.Y. Laligand throw new IllegalArgumentException("Route cannot be null."); 8979d93a378c5158d14f80d46af70433234330ec568P.Y. Laligand } 89869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown selectRouteStatic(types, route, true); 8990d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell } 90069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 9010d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell /** 9020d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * @hide internal use 9030d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell */ 90469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public void selectRouteInt(int types, RouteInfo route, boolean explicit) { 90569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown selectRouteStatic(types, route, explicit); 906b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn } 907b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn 9089d93a378c5158d14f80d46af70433234330ec568P.Y. Laligand static void selectRouteStatic(int types, @NonNull RouteInfo route, boolean explicit) { 90918687b7a275b3782e63d52cdbe8ee9df191046e7Jae Seo Log.v(TAG, "Selecting route: " + route); 9109d93a378c5158d14f80d46af70433234330ec568P.Y. Laligand assert(route != null); 911705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell final RouteInfo oldRoute = sStatic.mSelectedRoute; 912705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell if (oldRoute == route) return; 9130abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown if (!route.matchesTypes(types)) { 9140d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell Log.w(TAG, "selectRoute ignored; cannot select route with supported types " + 9150d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell typesToString(route.getSupportedTypes()) + " into route types " + 9160d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell typesToString(types)); 9174ee1f55ce0f4909a7430ab44563a81852f335071Adam Powell return; 9180d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell } 9199a1de308cea2d160778fd977825f10a07b49d738Adam Powell 920fa6f70e225a7370c1ecb21ee7076c9086ecb9e9aSungsoo final RouteInfo btRoute = sStatic.mBluetoothA2dpRoute; 921fa6f70e225a7370c1ecb21ee7076c9086ecb9e9aSungsoo if (btRoute != null && (types & ROUTE_TYPE_LIVE_AUDIO) != 0 && 922fa6f70e225a7370c1ecb21ee7076c9086ecb9e9aSungsoo (route == btRoute || route == sStatic.mDefaultAudioVideo)) { 923fa6f70e225a7370c1ecb21ee7076c9086ecb9e9aSungsoo try { 924fa6f70e225a7370c1ecb21ee7076c9086ecb9e9aSungsoo sStatic.mAudioService.setBluetoothA2dpOn(route == btRoute); 925fa6f70e225a7370c1ecb21ee7076c9086ecb9e9aSungsoo } catch (RemoteException e) { 926fa6f70e225a7370c1ecb21ee7076c9086ecb9e9aSungsoo Log.e(TAG, "Error changing Bluetooth A2DP state", e); 927fa6f70e225a7370c1ecb21ee7076c9086ecb9e9aSungsoo } 928fa6f70e225a7370c1ecb21ee7076c9086ecb9e9aSungsoo } 929fa6f70e225a7370c1ecb21ee7076c9086ecb9e9aSungsoo 930705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell final WifiDisplay activeDisplay = 931705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell sStatic.mDisplayService.getWifiDisplayStatus().getActiveDisplay(); 932705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell final boolean oldRouteHasAddress = oldRoute != null && oldRoute.mDeviceAddress != null; 9339d93a378c5158d14f80d46af70433234330ec568P.Y. Laligand final boolean newRouteHasAddress = route.mDeviceAddress != null; 934705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell if (activeDisplay != null || oldRouteHasAddress || newRouteHasAddress) { 935705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell if (newRouteHasAddress && !matchesDeviceAddress(activeDisplay, route)) { 936af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown if (sStatic.mCanConfigureWifiDisplays) { 937af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown sStatic.mDisplayService.connectWifiDisplay(route.mDeviceAddress); 938af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown } else { 939af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown Log.e(TAG, "Cannot connect to wifi displays because this process " 940af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown + "is not allowed to do so."); 941af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown } 942705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } else if (activeDisplay != null && !newRouteHasAddress) { 943705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell sStatic.mDisplayService.disconnectWifiDisplay(); 944705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 945705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 946705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 94769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown sStatic.setSelectedRoute(route, explicit); 94869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 949705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell if (oldRoute != null) { 950705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell dispatchRouteUnselected(types & oldRoute.getSupportedTypes(), oldRoute); 95139ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown if (oldRoute.resolveStatusCode()) { 95239ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown dispatchRouteChanged(oldRoute); 95339ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown } 9549a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 9559a1de308cea2d160778fd977825f10a07b49d738Adam Powell if (route != null) { 95639ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown if (route.resolveStatusCode()) { 95739ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown dispatchRouteChanged(route); 95839ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown } 9599a1de308cea2d160778fd977825f10a07b49d738Adam Powell dispatchRouteSelected(types & route.getSupportedTypes(), route); 9609a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 961ce468a35b388ca46578934706b38dbae94941643Jeff Brown 962ce468a35b388ca46578934706b38dbae94941643Jeff Brown // The behavior of active scans may depend on the currently selected route. 963ce468a35b388ca46578934706b38dbae94941643Jeff Brown sStatic.updateDiscoveryRequest(); 9649a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 9659a1de308cea2d160778fd977825f10a07b49d738Adam Powell 96669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown static void selectDefaultRouteStatic() { 96769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // TODO: Be smarter about the route types here; this selects for all valid. 96869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (sStatic.mSelectedRoute != sStatic.mBluetoothA2dpRoute 969fa6f70e225a7370c1ecb21ee7076c9086ecb9e9aSungsoo && sStatic.mBluetoothA2dpRoute != null && sStatic.isBluetoothA2dpOn()) { 97069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown selectRouteStatic(ROUTE_TYPE_ANY, sStatic.mBluetoothA2dpRoute, false); 97169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } else { 97269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown selectRouteStatic(ROUTE_TYPE_ANY, sStatic.mDefaultAudioVideo, false); 97369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 97469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 97569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 9769a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 977705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell * Compare the device address of a display and a route. 978705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell * Nulls/no device address will match another null/no address. 979705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell */ 980705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell static boolean matchesDeviceAddress(WifiDisplay display, RouteInfo info) { 981705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell final boolean routeHasAddress = info != null && info.mDeviceAddress != null; 982705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell if (display == null && !routeHasAddress) { 983705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell return true; 984705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 985705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 986705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell if (display != null && routeHasAddress) { 987705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell return display.getDeviceAddress().equals(info.mDeviceAddress); 988705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 989705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell return false; 990705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 991705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 992705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell /** 9939a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Add an app-specified route for media to the MediaRouter. 9949a1de308cea2d160778fd977825f10a07b49d738Adam Powell * App-specified route definitions are created using {@link #createUserRoute(RouteCategory)} 9959a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 9969a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param info Definition of the route to add 9973afc18af2cea898753b10e8575dcf20c11356bcaJeff Brown * @see #createUserRoute(RouteCategory) 9989a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @see #removeUserRoute(UserRouteInfo) 9999a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 10009a1de308cea2d160778fd977825f10a07b49d738Adam Powell public void addUserRoute(UserRouteInfo info) { 10012ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell addRouteStatic(info); 10029a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 10039a1de308cea2d160778fd977825f10a07b49d738Adam Powell 1004d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell /** 1005d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell * @hide Framework use only 1006d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell */ 1007d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell public void addRouteInt(RouteInfo info) { 10082ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell addRouteStatic(info); 1009d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell } 1010d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell 10112ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell static void addRouteStatic(RouteInfo info) { 101218687b7a275b3782e63d52cdbe8ee9df191046e7Jae Seo Log.v(TAG, "Adding route: " + info); 10139a1de308cea2d160778fd977825f10a07b49d738Adam Powell final RouteCategory cat = info.getCategory(); 1014b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn if (!sStatic.mCategories.contains(cat)) { 1015b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn sStatic.mCategories.add(cat); 10169a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 1017d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell if (cat.isGroupable() && !(info instanceof RouteGroup)) { 10189a1de308cea2d160778fd977825f10a07b49d738Adam Powell // Enforce that any added route in a groupable category must be in a group. 10199a1de308cea2d160778fd977825f10a07b49d738Adam Powell final RouteGroup group = new RouteGroup(info.getCategory()); 1020dbbfa702a09f6d2d36dee1b552442d04a4673f89Adam Powell group.mSupportedTypes = info.mSupportedTypes; 1021b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn sStatic.mRoutes.add(group); 1022d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell dispatchRouteAdded(group); 1023b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell group.addRoute(info); 1024d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell 10259a1de308cea2d160778fd977825f10a07b49d738Adam Powell info = group; 1026d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell } else { 1027b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn sStatic.mRoutes.add(info); 1028d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell dispatchRouteAdded(info); 10299a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 10309a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 10319a1de308cea2d160778fd977825f10a07b49d738Adam Powell 10329a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 10339a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Remove an app-specified route for media from the MediaRouter. 10349a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 10359a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param info Definition of the route to remove 10369a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @see #addUserRoute(UserRouteInfo) 10379a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 10389a1de308cea2d160778fd977825f10a07b49d738Adam Powell public void removeUserRoute(UserRouteInfo info) { 103969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown removeRouteStatic(info); 10409a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 10419a1de308cea2d160778fd977825f10a07b49d738Adam Powell 1042690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell /** 1043690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell * Remove all app-specified routes from the MediaRouter. 1044690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell * 1045690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell * @see #removeUserRoute(UserRouteInfo) 1046690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell */ 1047690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell public void clearUserRoutes() { 1048b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn for (int i = 0; i < sStatic.mRoutes.size(); i++) { 1049b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn final RouteInfo info = sStatic.mRoutes.get(i); 1050d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell // TODO Right now, RouteGroups only ever contain user routes. 1051d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell // The code below will need to change if this assumption does. 1052d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell if (info instanceof UserRouteInfo || info instanceof RouteGroup) { 105369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown removeRouteStatic(info); 1054690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell i--; 1055690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell } 1056690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell } 1057690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell } 1058690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell 1059d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell /** 1060d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell * @hide internal use only 1061d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell */ 1062d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell public void removeRouteInt(RouteInfo info) { 106369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown removeRouteStatic(info); 1064d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell } 1065d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell 106669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown static void removeRouteStatic(RouteInfo info) { 106718687b7a275b3782e63d52cdbe8ee9df191046e7Jae Seo Log.v(TAG, "Removing route: " + info); 1068b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn if (sStatic.mRoutes.remove(info)) { 10699a1de308cea2d160778fd977825f10a07b49d738Adam Powell final RouteCategory removingCat = info.getCategory(); 1070b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn final int count = sStatic.mRoutes.size(); 10719a1de308cea2d160778fd977825f10a07b49d738Adam Powell boolean found = false; 10729a1de308cea2d160778fd977825f10a07b49d738Adam Powell for (int i = 0; i < count; i++) { 1073b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn final RouteCategory cat = sStatic.mRoutes.get(i).getCategory(); 10749a1de308cea2d160778fd977825f10a07b49d738Adam Powell if (removingCat == cat) { 10759a1de308cea2d160778fd977825f10a07b49d738Adam Powell found = true; 10769a1de308cea2d160778fd977825f10a07b49d738Adam Powell break; 10779a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 10789a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 10790abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown if (info.isSelected()) { 1080d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell // Removing the currently selected route? Select the default before we remove it. 108169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown selectDefaultRouteStatic(); 1082d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell } 1083690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell if (!found) { 1084b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn sStatic.mCategories.remove(removingCat); 1085690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell } 1086690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell dispatchRouteRemoved(info); 1087690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell } 1088690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell } 1089690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell 10909a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 10919a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Return the number of {@link MediaRouter.RouteCategory categories} currently 10929a1de308cea2d160778fd977825f10a07b49d738Adam Powell * represented by routes known to this MediaRouter. 10939a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 10949a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @return the number of unique categories represented by this MediaRouter's known routes 10959a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 10969a1de308cea2d160778fd977825f10a07b49d738Adam Powell public int getCategoryCount() { 1097b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn return sStatic.mCategories.size(); 10989a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 10999a1de308cea2d160778fd977825f10a07b49d738Adam Powell 11009a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 11019a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Return the {@link MediaRouter.RouteCategory category} at the given index. 11029a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Valid indices are in the range [0-getCategoryCount). 11039a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 11049a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param index which category to return 11059a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @return the category at index 11069a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 11079a1de308cea2d160778fd977825f10a07b49d738Adam Powell public RouteCategory getCategoryAt(int index) { 1108b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn return sStatic.mCategories.get(index); 11099a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 11109a1de308cea2d160778fd977825f10a07b49d738Adam Powell 11119a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 11129a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Return the number of {@link MediaRouter.RouteInfo routes} currently known 11139a1de308cea2d160778fd977825f10a07b49d738Adam Powell * to this MediaRouter. 11149a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 11159a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @return the number of routes tracked by this router 11169a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 11179a1de308cea2d160778fd977825f10a07b49d738Adam Powell public int getRouteCount() { 1118b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn return sStatic.mRoutes.size(); 11199a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 11209a1de308cea2d160778fd977825f10a07b49d738Adam Powell 11219a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 11229a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Return the route at the specified index. 11239a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 11249a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param index index of the route to return 11259a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @return the route at index 11269a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 11279a1de308cea2d160778fd977825f10a07b49d738Adam Powell public RouteInfo getRouteAt(int index) { 1128b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn return sStatic.mRoutes.get(index); 1129b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn } 1130b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn 1131b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn static int getRouteCountStatic() { 1132b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn return sStatic.mRoutes.size(); 1133b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn } 1134b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn 1135b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn static RouteInfo getRouteAtStatic(int index) { 1136b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn return sStatic.mRoutes.get(index); 11379a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 11389a1de308cea2d160778fd977825f10a07b49d738Adam Powell 11399a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 11409a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Create a new user route that may be modified and registered for use by the application. 11419a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 11429a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param category The category the new route will belong to 11439a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @return A new UserRouteInfo for use by the application 11449a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 11459a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @see #addUserRoute(UserRouteInfo) 11469a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @see #removeUserRoute(UserRouteInfo) 114769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * @see #createRouteCategory(CharSequence, boolean) 11489a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 11499a1de308cea2d160778fd977825f10a07b49d738Adam Powell public UserRouteInfo createUserRoute(RouteCategory category) { 11509a1de308cea2d160778fd977825f10a07b49d738Adam Powell return new UserRouteInfo(category); 11519a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 11529a1de308cea2d160778fd977825f10a07b49d738Adam Powell 11539a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 11549a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Create a new route category. Each route must belong to a category. 11559a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 11569a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param name Name of the new category 11579a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param isGroupable true if routes in this category may be grouped with one another 11589a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @return the new RouteCategory 11599a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 11609a1de308cea2d160778fd977825f10a07b49d738Adam Powell public RouteCategory createRouteCategory(CharSequence name, boolean isGroupable) { 11619a1de308cea2d160778fd977825f10a07b49d738Adam Powell return new RouteCategory(name, ROUTE_TYPE_USER, isGroupable); 11629a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 11635d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik 11640d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell /** 11650d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * Create a new route category. Each route must belong to a category. 11660d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * 11670d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * @param nameResId Resource ID of the name of the new category 11680d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * @param isGroupable true if routes in this category may be grouped with one another 11690d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * @return the new RouteCategory 11700d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell */ 11710d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public RouteCategory createRouteCategory(int nameResId, boolean isGroupable) { 11720d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell return new RouteCategory(nameResId, ROUTE_TYPE_USER, isGroupable); 11730d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell } 11749a1de308cea2d160778fd977825f10a07b49d738Adam Powell 117569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown /** 117669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * Rebinds the media router to handle routes that belong to the specified user. 117769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * Requires the interact across users permission to access the routes of another user. 117869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * <p> 117969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * This method is a complete hack to work around the singleton nature of the 118069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * media router when running inside of singleton processes like QuickSettings. 118169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * This mechanism should be burned to the ground when MediaRouter is redesigned. 118269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * Ideally the current user would be pulled from the Context but we need to break 118369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * down MediaRouter.Static before we can get there. 118469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * </p> 118569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * 118669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * @hide 118769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown */ 118869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public void rebindAsUser(int userId) { 118969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown sStatic.rebindAsUser(userId); 119069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 119169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 1192b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn static void updateRoute(final RouteInfo info) { 11939a1de308cea2d160778fd977825f10a07b49d738Adam Powell dispatchRouteChanged(info); 11949a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 11959a1de308cea2d160778fd977825f10a07b49d738Adam Powell 1196b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn static void dispatchRouteSelected(int type, RouteInfo info) { 119739d5c6172503620ac3761148adac5fd7fa20d02dAdam Powell for (CallbackInfo cbi : sStatic.mCallbacks) { 119866f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown if (cbi.filterRouteEvent(info)) { 1199b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn cbi.cb.onRouteSelected(cbi.router, type, info); 12009a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 12019a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 12029a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 12039a1de308cea2d160778fd977825f10a07b49d738Adam Powell 1204b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn static void dispatchRouteUnselected(int type, RouteInfo info) { 120539d5c6172503620ac3761148adac5fd7fa20d02dAdam Powell for (CallbackInfo cbi : sStatic.mCallbacks) { 120666f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown if (cbi.filterRouteEvent(info)) { 1207b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn cbi.cb.onRouteUnselected(cbi.router, type, info); 12089a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 12099a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 12109a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 12119a1de308cea2d160778fd977825f10a07b49d738Adam Powell 1212b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn static void dispatchRouteChanged(RouteInfo info) { 1213af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown dispatchRouteChanged(info, info.mSupportedTypes); 1214af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown } 1215af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown 1216af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown static void dispatchRouteChanged(RouteInfo info, int oldSupportedTypes) { 121718687b7a275b3782e63d52cdbe8ee9df191046e7Jae Seo Log.v(TAG, "Dispatching route change: " + info); 1218af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown final int newSupportedTypes = info.mSupportedTypes; 121939d5c6172503620ac3761148adac5fd7fa20d02dAdam Powell for (CallbackInfo cbi : sStatic.mCallbacks) { 1220af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown // Reconstruct some of the history for callbacks that may not have observed 1221af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown // all of the events needed to correctly interpret the current state. 1222af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown // FIXME: This is a strong signal that we should deprecate route type filtering 1223af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown // completely in the future because it can lead to inconsistencies in 1224af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown // applications. 1225af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown final boolean oldVisibility = cbi.filterRouteEvent(oldSupportedTypes); 1226af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown final boolean newVisibility = cbi.filterRouteEvent(newSupportedTypes); 1227af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown if (!oldVisibility && newVisibility) { 1228af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown cbi.cb.onRouteAdded(cbi.router, info); 1229af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown if (info.isSelected()) { 1230af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown cbi.cb.onRouteSelected(cbi.router, newSupportedTypes, info); 1231af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown } 1232af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown } 1233af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown if (oldVisibility || newVisibility) { 1234b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn cbi.cb.onRouteChanged(cbi.router, info); 12359a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 1236af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown if (oldVisibility && !newVisibility) { 1237af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown if (info.isSelected()) { 1238af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown cbi.cb.onRouteUnselected(cbi.router, oldSupportedTypes, info); 1239af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown } 1240af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown cbi.cb.onRouteRemoved(cbi.router, info); 1241af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown } 12429a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 12439a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 12449a1de308cea2d160778fd977825f10a07b49d738Adam Powell 1245b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn static void dispatchRouteAdded(RouteInfo info) { 124639d5c6172503620ac3761148adac5fd7fa20d02dAdam Powell for (CallbackInfo cbi : sStatic.mCallbacks) { 124766f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown if (cbi.filterRouteEvent(info)) { 1248b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn cbi.cb.onRouteAdded(cbi.router, info); 12499a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 12509a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 12519a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 12529a1de308cea2d160778fd977825f10a07b49d738Adam Powell 1253b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn static void dispatchRouteRemoved(RouteInfo info) { 125439d5c6172503620ac3761148adac5fd7fa20d02dAdam Powell for (CallbackInfo cbi : sStatic.mCallbacks) { 125566f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown if (cbi.filterRouteEvent(info)) { 1256b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn cbi.cb.onRouteRemoved(cbi.router, info); 12579a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 12589a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 12599a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 12609a1de308cea2d160778fd977825f10a07b49d738Adam Powell 1261b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn static void dispatchRouteGrouped(RouteInfo info, RouteGroup group, int index) { 126239d5c6172503620ac3761148adac5fd7fa20d02dAdam Powell for (CallbackInfo cbi : sStatic.mCallbacks) { 126366f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown if (cbi.filterRouteEvent(group)) { 1264b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn cbi.cb.onRouteGrouped(cbi.router, info, group, index); 1265d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell } 1266d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell } 1267d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell } 1268d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell 1269b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn static void dispatchRouteUngrouped(RouteInfo info, RouteGroup group) { 127039d5c6172503620ac3761148adac5fd7fa20d02dAdam Powell for (CallbackInfo cbi : sStatic.mCallbacks) { 127166f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown if (cbi.filterRouteEvent(group)) { 1272b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn cbi.cb.onRouteUngrouped(cbi.router, info, group); 12739a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 12749a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 12759a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 12769a1de308cea2d160778fd977825f10a07b49d738Adam Powell 12778e37a85bf3dc39519942698dc90a3951306b934bAdam Powell static void dispatchRouteVolumeChanged(RouteInfo info) { 12788e37a85bf3dc39519942698dc90a3951306b934bAdam Powell for (CallbackInfo cbi : sStatic.mCallbacks) { 127966f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown if (cbi.filterRouteEvent(info)) { 12808e37a85bf3dc39519942698dc90a3951306b934bAdam Powell cbi.cb.onRouteVolumeChanged(cbi.router, info); 12818e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 12828e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 12838e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 12848e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 128592130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown static void dispatchRoutePresentationDisplayChanged(RouteInfo info) { 128692130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown for (CallbackInfo cbi : sStatic.mCallbacks) { 128766f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown if (cbi.filterRouteEvent(info)) { 128892130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown cbi.cb.onRoutePresentationDisplayChanged(cbi.router, info); 128992130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown } 129092130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown } 129192130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown } 129292130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown 12938e37a85bf3dc39519942698dc90a3951306b934bAdam Powell static void systemVolumeChanged(int newValue) { 12948e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final RouteInfo selectedRoute = sStatic.mSelectedRoute; 12958e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (selectedRoute == null) return; 12968e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 12978e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (selectedRoute == sStatic.mBluetoothA2dpRoute || 1298705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell selectedRoute == sStatic.mDefaultAudioVideo) { 12998e37a85bf3dc39519942698dc90a3951306b934bAdam Powell dispatchRouteVolumeChanged(selectedRoute); 13008e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } else if (sStatic.mBluetoothA2dpRoute != null) { 1301fa6f70e225a7370c1ecb21ee7076c9086ecb9e9aSungsoo try { 1302fa6f70e225a7370c1ecb21ee7076c9086ecb9e9aSungsoo dispatchRouteVolumeChanged(sStatic.mAudioService.isBluetoothA2dpOn() ? 1303fa6f70e225a7370c1ecb21ee7076c9086ecb9e9aSungsoo sStatic.mBluetoothA2dpRoute : sStatic.mDefaultAudioVideo); 1304fa6f70e225a7370c1ecb21ee7076c9086ecb9e9aSungsoo } catch (RemoteException e) { 1305fa6f70e225a7370c1ecb21ee7076c9086ecb9e9aSungsoo Log.e(TAG, "Error checking Bluetooth A2DP state to report volume change", e); 1306fa6f70e225a7370c1ecb21ee7076c9086ecb9e9aSungsoo } 13078e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } else { 1308705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell dispatchRouteVolumeChanged(sStatic.mDefaultAudioVideo); 1309705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1310705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1311705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 131275af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown static void updateWifiDisplayStatus(WifiDisplayStatus status) { 131375af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown WifiDisplay[] displays; 1314615e413a90ff5898d8c458ebc9649ca95fa9fd98Adam Powell WifiDisplay activeDisplay; 131575af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown if (status.getFeatureState() == WifiDisplayStatus.FEATURE_STATE_ON) { 131675af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown displays = status.getDisplays(); 131775af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown activeDisplay = status.getActiveDisplay(); 1318af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown 1319af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown // Only the system is able to connect to wifi display routes. 1320af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown // The display manager will enforce this with a permission check but it 1321af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown // still publishes information about all available displays. 1322af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown // Filter the list down to just the active display. 1323af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown if (!sStatic.mCanConfigureWifiDisplays) { 1324af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown if (activeDisplay != null) { 1325af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown displays = new WifiDisplay[] { activeDisplay }; 1326af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown } else { 1327af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown displays = WifiDisplay.EMPTY_ARRAY; 1328af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown } 1329af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown } 1330615e413a90ff5898d8c458ebc9649ca95fa9fd98Adam Powell } else { 133175af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown displays = WifiDisplay.EMPTY_ARRAY; 1332615e413a90ff5898d8c458ebc9649ca95fa9fd98Adam Powell activeDisplay = null; 1333615e413a90ff5898d8c458ebc9649ca95fa9fd98Adam Powell } 1334ce468a35b388ca46578934706b38dbae94941643Jeff Brown String activeDisplayAddress = activeDisplay != null ? 1335ce468a35b388ca46578934706b38dbae94941643Jeff Brown activeDisplay.getDeviceAddress() : null; 1336705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 133775af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown // Add or update routes. 133875af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown for (int i = 0; i < displays.length; i++) { 133975af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown final WifiDisplay d = displays[i]; 134075af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown if (shouldShowWifiDisplay(d, activeDisplay)) { 1341ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang RouteInfo route = findWifiDisplayRoute(d); 1342ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang if (route == null) { 134375af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown route = makeWifiDisplayRoute(d, status); 1344ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang addRouteStatic(route); 1345ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang } else { 1346ce468a35b388ca46578934706b38dbae94941643Jeff Brown String address = d.getDeviceAddress(); 1347ce468a35b388ca46578934706b38dbae94941643Jeff Brown boolean disconnected = !address.equals(activeDisplayAddress) 1348ce468a35b388ca46578934706b38dbae94941643Jeff Brown && address.equals(sStatic.mPreviousActiveWifiDisplayAddress); 1349ce468a35b388ca46578934706b38dbae94941643Jeff Brown updateWifiDisplayRoute(route, d, status, disconnected); 1350ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang } 1351ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang if (d.equals(activeDisplay)) { 135269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown selectRouteStatic(route.getSupportedTypes(), route, false); 1353ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang } 13542ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell } 1355705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 135675af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown 135775af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown // Remove stale routes. 135875af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown for (int i = sStatic.mRoutes.size(); i-- > 0; ) { 135975af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown RouteInfo route = sStatic.mRoutes.get(i); 136075af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown if (route.mDeviceAddress != null) { 136175af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown WifiDisplay d = findWifiDisplay(displays, route.mDeviceAddress); 136275af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown if (d == null || !shouldShowWifiDisplay(d, activeDisplay)) { 136375af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown removeRouteStatic(route); 1364ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang } 1365705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1366705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1367ce468a35b388ca46578934706b38dbae94941643Jeff Brown 1368ce468a35b388ca46578934706b38dbae94941643Jeff Brown // Remember the current active wifi display address so that we can infer disconnections. 1369ce468a35b388ca46578934706b38dbae94941643Jeff Brown // TODO: This hack will go away once all of this is moved into the media router service. 1370ce468a35b388ca46578934706b38dbae94941643Jeff Brown sStatic.mPreviousActiveWifiDisplayAddress = activeDisplayAddress; 137175af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown } 1372705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 137375af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown private static boolean shouldShowWifiDisplay(WifiDisplay d, WifiDisplay activeDisplay) { 137475af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown return d.isRemembered() || d.equals(activeDisplay); 1375705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1376705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 1377ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang static int getWifiDisplayStatusCode(WifiDisplay d, WifiDisplayStatus wfdStatus) { 137869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown int newStatus; 1379ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang if (wfdStatus.getScanState() == WifiDisplayStatus.SCAN_STATE_SCANNING) { 1380ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang newStatus = RouteInfo.STATUS_SCANNING; 1381ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang } else if (d.isAvailable()) { 1382ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang newStatus = d.canConnect() ? 1383ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang RouteInfo.STATUS_AVAILABLE: RouteInfo.STATUS_IN_USE; 1384705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } else { 1385705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell newStatus = RouteInfo.STATUS_NOT_AVAILABLE; 1386705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1387705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 1388ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang if (d.equals(wfdStatus.getActiveDisplay())) { 1389ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang final int activeState = wfdStatus.getActiveDisplayState(); 1390705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell switch (activeState) { 1391705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell case WifiDisplayStatus.DISPLAY_STATE_CONNECTED: 139269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown newStatus = RouteInfo.STATUS_CONNECTED; 1393705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell break; 1394705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell case WifiDisplayStatus.DISPLAY_STATE_CONNECTING: 1395705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell newStatus = RouteInfo.STATUS_CONNECTING; 1396705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell break; 1397705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell case WifiDisplayStatus.DISPLAY_STATE_NOT_CONNECTED: 1398705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell Log.e(TAG, "Active display is not connected!"); 1399705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell break; 1400705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1401705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1402705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 1403ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang return newStatus; 1404ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang } 1405ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang 1406ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang static boolean isWifiDisplayEnabled(WifiDisplay d, WifiDisplayStatus wfdStatus) { 1407ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang return d.isAvailable() && (d.canConnect() || d.equals(wfdStatus.getActiveDisplay())); 1408ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang } 1409ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang 1410ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang static RouteInfo makeWifiDisplayRoute(WifiDisplay display, WifiDisplayStatus wfdStatus) { 1411ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang final RouteInfo newRoute = new RouteInfo(sStatic.mSystemCategory); 1412ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang newRoute.mDeviceAddress = display.getDeviceAddress(); 141369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown newRoute.mSupportedTypes = ROUTE_TYPE_LIVE_AUDIO | ROUTE_TYPE_LIVE_VIDEO 141469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown | ROUTE_TYPE_REMOTE_DISPLAY; 1415ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang newRoute.mVolumeHandling = RouteInfo.PLAYBACK_VOLUME_FIXED; 1416ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang newRoute.mPlaybackType = RouteInfo.PLAYBACK_TYPE_REMOTE; 1417ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang 141839ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown newRoute.setRealStatusCode(getWifiDisplayStatusCode(display, wfdStatus)); 1419ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang newRoute.mEnabled = isWifiDisplayEnabled(display, wfdStatus); 1420ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang newRoute.mName = display.getFriendlyDisplayName(); 1421ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang newRoute.mDescription = sStatic.mResources.getText( 1422ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang com.android.internal.R.string.wireless_display_route_description); 14235830b0b33618940d65197cec99d697b21908fec8Chong Zhang newRoute.updatePresentationDisplay(); 14249dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang newRoute.mDeviceType = RouteInfo.DEVICE_TYPE_TV; 1425ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang return newRoute; 1426ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang } 1427ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang 1428ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang private static void updateWifiDisplayRoute( 1429ce468a35b388ca46578934706b38dbae94941643Jeff Brown RouteInfo route, WifiDisplay display, WifiDisplayStatus wfdStatus, 1430ce468a35b388ca46578934706b38dbae94941643Jeff Brown boolean disconnected) { 1431ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang boolean changed = false; 14322444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown final String newName = display.getFriendlyDisplayName(); 14332444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown if (!route.getName().equals(newName)) { 1434705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell route.mName = newName; 1435705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell changed = true; 1436705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1437705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 1438ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang boolean enabled = isWifiDisplayEnabled(display, wfdStatus); 1439ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang changed |= route.mEnabled != enabled; 1440ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang route.mEnabled = enabled; 1441705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 144239ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown changed |= route.setRealStatusCode(getWifiDisplayStatusCode(display, wfdStatus)); 1443705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 1444705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell if (changed) { 1445705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell dispatchRouteChanged(route); 1446705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1447705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 1448ce468a35b388ca46578934706b38dbae94941643Jeff Brown if ((!enabled || disconnected) && route.isSelected()) { 1449705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell // Oops, no longer available. Reselect the default. 145069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown selectDefaultRouteStatic(); 1451705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1452705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1453705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 145475af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown private static WifiDisplay findWifiDisplay(WifiDisplay[] displays, String deviceAddress) { 1455705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell for (int i = 0; i < displays.length; i++) { 145675af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown final WifiDisplay d = displays[i]; 145775af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown if (d.getDeviceAddress().equals(deviceAddress)) { 145875af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown return d; 1459705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1460705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1461705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell return null; 1462705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1463705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 1464705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell private static RouteInfo findWifiDisplayRoute(WifiDisplay d) { 1465705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell final int count = sStatic.mRoutes.size(); 1466705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell for (int i = 0; i < count; i++) { 1467705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell final RouteInfo info = sStatic.mRoutes.get(i); 1468705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell if (d.getDeviceAddress().equals(info.mDeviceAddress)) { 1469705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell return info; 1470705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1471705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1472705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell return null; 14738e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 14748e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 14759a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 14769a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Information about a media route. 14779a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 1478b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn public static class RouteInfo { 14799a1de308cea2d160778fd977825f10a07b49d738Adam Powell CharSequence mName; 14800d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell int mNameResId; 148156d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown CharSequence mDescription; 14829a1de308cea2d160778fd977825f10a07b49d738Adam Powell private CharSequence mStatus; 14839a1de308cea2d160778fd977825f10a07b49d738Adam Powell int mSupportedTypes; 14849dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang int mDeviceType; 14859a1de308cea2d160778fd977825f10a07b49d738Adam Powell RouteGroup mGroup; 14869a1de308cea2d160778fd977825f10a07b49d738Adam Powell final RouteCategory mCategory; 1487ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell Drawable mIcon; 14881357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi // playback information 14891357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi int mPlaybackType = PLAYBACK_TYPE_LOCAL; 14901357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi int mVolumeMax = RemoteControlClient.DEFAULT_PLAYBACK_VOLUME; 14911357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi int mVolume = RemoteControlClient.DEFAULT_PLAYBACK_VOLUME; 14921357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi int mVolumeHandling = RemoteControlClient.DEFAULT_PLAYBACK_VOLUME_HANDLING; 14931357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi int mPlaybackStream = AudioManager.STREAM_MUSIC; 14941357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi VolumeCallbackInfo mVcb; 149592130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown Display mPresentationDisplay; 14965830b0b33618940d65197cec99d697b21908fec8Chong Zhang int mPresentationDisplayId = -1; 14979a1de308cea2d160778fd977825f10a07b49d738Adam Powell 1498705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell String mDeviceAddress; 1499705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell boolean mEnabled = true; 1500705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 150169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // An id by which the route is known to the media router service. 150269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Null if this route only exists as an artifact within this process. 150369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown String mGlobalRouteId; 150469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 1505705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell // A predetermined connection status that can override mStatus 150639ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown private int mRealStatusCode; 150739ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown private int mResolvedStatusCode; 1508705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 15092ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell /** @hide */ public static final int STATUS_NONE = 0; 15102ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell /** @hide */ public static final int STATUS_SCANNING = 1; 15112ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell /** @hide */ public static final int STATUS_CONNECTING = 2; 15122ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell /** @hide */ public static final int STATUS_AVAILABLE = 3; 15132ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell /** @hide */ public static final int STATUS_NOT_AVAILABLE = 4; 1514ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang /** @hide */ public static final int STATUS_IN_USE = 5; 151569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown /** @hide */ public static final int STATUS_CONNECTED = 6; 1516705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 15179dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang /** @hide */ 15189dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang @IntDef({DEVICE_TYPE_UNKNOWN, DEVICE_TYPE_TV, DEVICE_TYPE_SPEAKER, DEVICE_TYPE_BLUETOOTH}) 15199dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang @Retention(RetentionPolicy.SOURCE) 15209dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang public @interface DeviceType {} 15219dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang 15229dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang /** 15239dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang * The default receiver device type of the route indicating the type is unknown. 15249dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang * 15259dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang * @see #getDeviceType 15269dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang */ 15279dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang public static final int DEVICE_TYPE_UNKNOWN = 0; 15289dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang 15299dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang /** 15309dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang * A receiver device type of the route indicating the presentation of the media is happening 15319dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang * on a TV. 15329dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang * 15339dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang * @see #getDeviceType 15349dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang */ 15359dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang public static final int DEVICE_TYPE_TV = 1; 15369dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang 15379dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang /** 15389dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang * A receiver device type of the route indicating the presentation of the media is happening 15399dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang * on a speaker. 15409dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang * 15419dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang * @see #getDeviceType 15429dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang */ 15439dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang public static final int DEVICE_TYPE_SPEAKER = 2; 15449dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang 15459dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang /** 15469dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang * A receiver device type of the route indicating the presentation of the media is happening 15479dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang * on a bluetooth device such as a bluetooth speaker. 15489dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang * 15499dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang * @see #getDeviceType 15509dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang */ 15519dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang public static final int DEVICE_TYPE_BLUETOOTH = 3; 15529dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang 1553b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell private Object mTag; 1554b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell 15557c090d54e2c0eb5309d3f7dc131e137d9c986793Insun Kang /** @hide */ 15567c090d54e2c0eb5309d3f7dc131e137d9c986793Insun Kang @IntDef({PLAYBACK_TYPE_LOCAL, PLAYBACK_TYPE_REMOTE}) 15577c090d54e2c0eb5309d3f7dc131e137d9c986793Insun Kang @Retention(RetentionPolicy.SOURCE) 15587c090d54e2c0eb5309d3f7dc131e137d9c986793Insun Kang public @interface PlaybackType {} 15597c090d54e2c0eb5309d3f7dc131e137d9c986793Insun Kang 15601357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 15611357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * The default playback type, "local", indicating the presentation of the media is happening 1562bc4cf00dc5bf6e0e3c01206d5c46e64306df260aJohn Spurlock * on the same device (e.g. a phone, a tablet) as where it is controlled from. 156369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * @see #getPlaybackType() 15641357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 15651357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public final static int PLAYBACK_TYPE_LOCAL = 0; 15667c090d54e2c0eb5309d3f7dc131e137d9c986793Insun Kang 15671357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 15681357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * A playback type indicating the presentation of the media is happening on 1569bc4cf00dc5bf6e0e3c01206d5c46e64306df260aJohn Spurlock * a different device (i.e. the remote device) than where it is controlled from. 157069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * @see #getPlaybackType() 15711357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 15721357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public final static int PLAYBACK_TYPE_REMOTE = 1; 15737c090d54e2c0eb5309d3f7dc131e137d9c986793Insun Kang 15747c090d54e2c0eb5309d3f7dc131e137d9c986793Insun Kang /** @hide */ 15757c090d54e2c0eb5309d3f7dc131e137d9c986793Insun Kang @IntDef({PLAYBACK_VOLUME_FIXED,PLAYBACK_VOLUME_VARIABLE}) 15767c090d54e2c0eb5309d3f7dc131e137d9c986793Insun Kang @Retention(RetentionPolicy.SOURCE) 15777c090d54e2c0eb5309d3f7dc131e137d9c986793Insun Kang private @interface PlaybackVolume {} 15787c090d54e2c0eb5309d3f7dc131e137d9c986793Insun Kang 15791357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 1580bc4cf00dc5bf6e0e3c01206d5c46e64306df260aJohn Spurlock * Playback information indicating the playback volume is fixed, i.e. it cannot be 15811357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * controlled from this object. An example of fixed playback volume is a remote player, 15821357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * playing over HDMI where the user prefers to control the volume on the HDMI sink, rather 15831357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * than attenuate at the source. 158469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * @see #getVolumeHandling() 15851357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 15861357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public final static int PLAYBACK_VOLUME_FIXED = 0; 15871357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 15881357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * Playback information indicating the playback volume is variable and can be controlled 15891357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * from this object. 159069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * @see #getVolumeHandling() 15911357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 15921357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public final static int PLAYBACK_VOLUME_VARIABLE = 1; 15931357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 15949a1de308cea2d160778fd977825f10a07b49d738Adam Powell RouteInfo(RouteCategory category) { 15959a1de308cea2d160778fd977825f10a07b49d738Adam Powell mCategory = category; 15969dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang mDeviceType = DEVICE_TYPE_UNKNOWN; 15979a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 15989a1de308cea2d160778fd977825f10a07b49d738Adam Powell 15999a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 160056d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * Gets the user-visible name of the route. 160156d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * <p> 160256d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * The route name identifies the destination represented by the route. 160356d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * It may be a user-supplied name, an alias, or device serial number. 160456d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * </p> 160556d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * 160656d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * @return The user-visible name of a media route. This is the string presented 16079a1de308cea2d160778fd977825f10a07b49d738Adam Powell * to users who may select this as the active route. 16089a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 16099a1de308cea2d160778fd977825f10a07b49d738Adam Powell public CharSequence getName() { 16100d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell return getName(sStatic.mResources); 16110d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell } 161256d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown 16130d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell /** 161456d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * Return the properly localized/resource user-visible name of this route. 161556d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * <p> 161656d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * The route name identifies the destination represented by the route. 161756d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * It may be a user-supplied name, an alias, or device serial number. 161856d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * </p> 161956d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * 16200d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * @param context Context used to resolve the correct configuration to load 162156d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * @return The user-visible name of a media route. This is the string presented 16220d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * to users who may select this as the active route. 16230d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell */ 16240d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public CharSequence getName(Context context) { 16250d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell return getName(context.getResources()); 16260d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell } 162756d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown 16280d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell CharSequence getName(Resources res) { 16290d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell if (mNameResId != 0) { 16300d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell return mName = res.getText(mNameResId); 16310d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell } 16329a1de308cea2d160778fd977825f10a07b49d738Adam Powell return mName; 16339a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 16349a1de308cea2d160778fd977825f10a07b49d738Adam Powell 16359a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 163656d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * Gets the user-visible description of the route. 163756d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * <p> 163856d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * The route description describes the kind of destination represented by the route. 163956d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * It may be a user-supplied string, a model number or brand of device. 164056d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * </p> 164156d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * 164256d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * @return The description of the route, or null if none. 164356d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown */ 164456d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown public CharSequence getDescription() { 164556d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown return mDescription; 164656d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown } 164756d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown 164856d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown /** 164956d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * @return The user-visible status for a media route. This may include a description 16509a1de308cea2d160778fd977825f10a07b49d738Adam Powell * of the currently playing media, if available. 16519a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 16529a1de308cea2d160778fd977825f10a07b49d738Adam Powell public CharSequence getStatus() { 16539a1de308cea2d160778fd977825f10a07b49d738Adam Powell return mStatus; 16549a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 16559a1de308cea2d160778fd977825f10a07b49d738Adam Powell 16569a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 1657705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell * Set this route's status by predetermined status code. If the caller 1658705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell * should dispatch a route changed event this call will return true; 1659705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell */ 166039ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown boolean setRealStatusCode(int statusCode) { 166139ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown if (mRealStatusCode != statusCode) { 166239ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown mRealStatusCode = statusCode; 166339ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown return resolveStatusCode(); 166439ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown } 166539ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown return false; 166639ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown } 166739ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown 166839ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown /** 166939ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown * Resolves the status code whenever the real status code or selection state 167039ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown * changes. 167139ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown */ 167239ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown boolean resolveStatusCode() { 167339ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown int statusCode = mRealStatusCode; 167439ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown if (isSelected()) { 1675705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell switch (statusCode) { 167639ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown // If the route is selected and its status appears to be between states 167739ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown // then report it as connecting even though it has not yet had a chance 167839ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown // to officially move into the CONNECTING state. Note that routes in 167939ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown // the NONE state are assumed to not require an explicit connection 168039ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown // lifecycle whereas those that are AVAILABLE are assumed to have 168139ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown // to eventually proceed to CONNECTED. 1682705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell case STATUS_AVAILABLE: 168339ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown case STATUS_SCANNING: 168439ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown statusCode = STATUS_CONNECTING; 168569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown break; 1686705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1687705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 168839ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown if (mResolvedStatusCode == statusCode) { 168939ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown return false; 169039ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown } 169139ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown 169239ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown mResolvedStatusCode = statusCode; 169339ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown int resId; 169439ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown switch (statusCode) { 169539ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown case STATUS_SCANNING: 169639ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown resId = com.android.internal.R.string.media_route_status_scanning; 169739ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown break; 169839ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown case STATUS_CONNECTING: 169939ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown resId = com.android.internal.R.string.media_route_status_connecting; 170039ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown break; 170139ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown case STATUS_AVAILABLE: 170239ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown resId = com.android.internal.R.string.media_route_status_available; 170339ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown break; 170439ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown case STATUS_NOT_AVAILABLE: 170539ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown resId = com.android.internal.R.string.media_route_status_not_available; 170639ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown break; 170739ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown case STATUS_IN_USE: 170839ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown resId = com.android.internal.R.string.media_route_status_in_use; 170939ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown break; 171039ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown case STATUS_CONNECTED: 171139ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown case STATUS_NONE: 171239ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown default: 171339ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown resId = 0; 171439ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown break; 171539ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown } 171639ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown mStatus = resId != 0 ? sStatic.mResources.getText(resId) : null; 171739ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown return true; 1718705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1719705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 1720705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell /** 17212ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell * @hide 17222ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell */ 17232ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell public int getStatusCode() { 172439ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown return mResolvedStatusCode; 17252ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell } 17262ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell 17272ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell /** 17289a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @return A media type flag set describing which types this route supports. 17299a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 17309a1de308cea2d160778fd977825f10a07b49d738Adam Powell public int getSupportedTypes() { 17319a1de308cea2d160778fd977825f10a07b49d738Adam Powell return mSupportedTypes; 17329a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 17339a1de308cea2d160778fd977825f10a07b49d738Adam Powell 17349dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang /** 17359dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang * Gets the type of the receiver device associated with this route. 17369dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang * 17379dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang * @return The type of the receiver device associated with this route: 17389dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang * {@link #DEVICE_TYPE_BLUETOOTH}, {@link #DEVICE_TYPE_TV}, {@link #DEVICE_TYPE_SPEAKER}, 17399dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang * or {@link #DEVICE_TYPE_UNKNOWN}. 17409dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang */ 17419dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang @DeviceType 17429dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang public int getDeviceType() { 17439dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang return mDeviceType; 17449dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang } 17459dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang 17460abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown /** @hide */ 17470abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown public boolean matchesTypes(int types) { 17480abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown return (mSupportedTypes & types) != 0; 17490abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown } 17500abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown 17519a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 17529a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @return The group that this route belongs to. 17539a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 17549a1de308cea2d160778fd977825f10a07b49d738Adam Powell public RouteGroup getGroup() { 17559a1de308cea2d160778fd977825f10a07b49d738Adam Powell return mGroup; 17569a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 17579a1de308cea2d160778fd977825f10a07b49d738Adam Powell 17589a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 17599a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @return the category this route belongs to. 17609a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 17619a1de308cea2d160778fd977825f10a07b49d738Adam Powell public RouteCategory getCategory() { 17629a1de308cea2d160778fd977825f10a07b49d738Adam Powell return mCategory; 17639a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 17649a1de308cea2d160778fd977825f10a07b49d738Adam Powell 1765ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell /** 1766ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * Get the icon representing this route. 1767ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * This icon will be used in picker UIs if available. 1768ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * 1769ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * @return the icon representing this route or null if no icon is available 1770ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell */ 1771ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell public Drawable getIconDrawable() { 1772ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell return mIcon; 1773ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell } 1774ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell 1775b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell /** 1776b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell * Set an application-specific tag object for this route. 1777b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell * The application may use this to store arbitrary data associated with the 1778b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell * route for internal tracking. 1779b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell * 1780b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell * <p>Note that the lifespan of a route may be well past the lifespan of 1781b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell * an Activity or other Context; take care that objects you store here 1782b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell * will not keep more data in memory alive than you intend.</p> 1783b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell * 1784b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell * @param tag Arbitrary, app-specific data for this route to hold for later use 1785b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell */ 1786b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell public void setTag(Object tag) { 1787b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell mTag = tag; 1788130b4572d1f3df702e5b296a655d15a41f6d4c66Adam Powell routeUpdated(); 1789b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell } 1790b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell 1791b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell /** 1792b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell * @return The tag object previously set by the application 1793b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell * @see #setTag(Object) 1794b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell */ 1795b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell public Object getTag() { 1796b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell return mTag; 1797b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell } 1798b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell 17991357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 18001357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @return the type of playback associated with this route 18011357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @see UserRouteInfo#setPlaybackType(int) 18021357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 18037c090d54e2c0eb5309d3f7dc131e137d9c986793Insun Kang @PlaybackType 18041357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public int getPlaybackType() { 18051357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi return mPlaybackType; 18061357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 18071357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 18081357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 18091357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @return the stream over which the playback associated with this route is performed 18101357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @see UserRouteInfo#setPlaybackStream(int) 18111357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 18121357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public int getPlaybackStream() { 18131357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi return mPlaybackStream; 18141357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 18151357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 18161357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 18178e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * Return the current volume for this route. Depending on the route, this may only 18188e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * be valid if the route is currently selected. 18198e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * 18201357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @return the volume at which the playback associated with this route is performed 18211357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @see UserRouteInfo#setVolume(int) 18221357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 18231357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public int getVolume() { 18241357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi if (mPlaybackType == PLAYBACK_TYPE_LOCAL) { 18251357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi int vol = 0; 18261357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi try { 18271357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi vol = sStatic.mAudioService.getStreamVolume(mPlaybackStream); 18281357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } catch (RemoteException e) { 18291357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi Log.e(TAG, "Error getting local stream volume", e); 18301357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 18311357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi return vol; 18321357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } else { 18331357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi return mVolume; 18341357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 18351357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 18361357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 18371357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 18388e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * Request a volume change for this route. 18398e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * @param volume value between 0 and getVolumeMax 18408e37a85bf3dc39519942698dc90a3951306b934bAdam Powell */ 18418e37a85bf3dc39519942698dc90a3951306b934bAdam Powell public void requestSetVolume(int volume) { 18428e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (mPlaybackType == PLAYBACK_TYPE_LOCAL) { 18438e37a85bf3dc39519942698dc90a3951306b934bAdam Powell try { 1844ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn sStatic.mAudioService.setStreamVolume(mPlaybackStream, volume, 0, 1845ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn ActivityThread.currentPackageName()); 18468e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } catch (RemoteException e) { 18478e37a85bf3dc39519942698dc90a3951306b934bAdam Powell Log.e(TAG, "Error setting local stream volume", e); 18488e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 18498e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } else { 185069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown sStatic.requestSetVolume(this, volume); 18518e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 18528e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 18538e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 18548e37a85bf3dc39519942698dc90a3951306b934bAdam Powell /** 18558e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * Request an incremental volume update for this route. 18568e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * @param direction Delta to apply to the current volume 18578e37a85bf3dc39519942698dc90a3951306b934bAdam Powell */ 18588e37a85bf3dc39519942698dc90a3951306b934bAdam Powell public void requestUpdateVolume(int direction) { 18598e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (mPlaybackType == PLAYBACK_TYPE_LOCAL) { 18608e37a85bf3dc39519942698dc90a3951306b934bAdam Powell try { 18618e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final int volume = 18628e37a85bf3dc39519942698dc90a3951306b934bAdam Powell Math.max(0, Math.min(getVolume() + direction, getVolumeMax())); 1863ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn sStatic.mAudioService.setStreamVolume(mPlaybackStream, volume, 0, 1864ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn ActivityThread.currentPackageName()); 18658e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } catch (RemoteException e) { 18668e37a85bf3dc39519942698dc90a3951306b934bAdam Powell Log.e(TAG, "Error setting local stream volume", e); 18678e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 18688e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } else { 186969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown sStatic.requestUpdateVolume(this, direction); 18708e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 18718e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 18728e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 18738e37a85bf3dc39519942698dc90a3951306b934bAdam Powell /** 18741357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @return the maximum volume at which the playback associated with this route is performed 18751357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @see UserRouteInfo#setVolumeMax(int) 18761357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 18771357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public int getVolumeMax() { 18781357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi if (mPlaybackType == PLAYBACK_TYPE_LOCAL) { 18791357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi int volMax = 0; 18801357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi try { 18811357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi volMax = sStatic.mAudioService.getStreamMaxVolume(mPlaybackStream); 18821357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } catch (RemoteException e) { 18831357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi Log.e(TAG, "Error getting local stream volume", e); 18841357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 18851357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi return volMax; 18861357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } else { 18871357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi return mVolumeMax; 18881357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 18891357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 18901357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 18911357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 18921357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @return how volume is handling on the route 18931357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @see UserRouteInfo#setVolumeHandling(int) 18941357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 18957c090d54e2c0eb5309d3f7dc131e137d9c986793Insun Kang @PlaybackVolume 18961357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public int getVolumeHandling() { 18971357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi return mVolumeHandling; 18981357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 18991357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 1900705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell /** 190192130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * Gets the {@link Display} that should be used by the application to show 190292130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * a {@link android.app.Presentation} on an external display when this route is selected. 190392130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * Depending on the route, this may only be valid if the route is currently 190492130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * selected. 190592130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * <p> 190692130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * The preferred presentation display may change independently of the route 190792130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * being selected or unselected. For example, the presentation display 190892130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * of the default system route may change when an external HDMI display is connected 190992130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * or disconnected even though the route itself has not changed. 191092130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * </p><p> 191192130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * This method may return null if there is no external display associated with 191292130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * the route or if the display is not ready to show UI yet. 191392130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * </p><p> 191492130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * The application should listen for changes to the presentation display 191592130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * using the {@link Callback#onRoutePresentationDisplayChanged} callback and 191692130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * show or dismiss its {@link android.app.Presentation} accordingly when the display 191792130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * becomes available or is removed. 191892130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * </p><p> 191992130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * This method only makes sense for {@link #ROUTE_TYPE_LIVE_VIDEO live video} routes. 192092130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * </p> 192192130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * 192292130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * @return The preferred presentation display to use when this route is 192392130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * selected or null if none. 192492130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * 192592130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * @see #ROUTE_TYPE_LIVE_VIDEO 192692130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * @see android.app.Presentation 192792130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown */ 192892130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown public Display getPresentationDisplay() { 192992130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown return mPresentationDisplay; 193092130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown } 193192130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown 19325830b0b33618940d65197cec99d697b21908fec8Chong Zhang boolean updatePresentationDisplay() { 19335830b0b33618940d65197cec99d697b21908fec8Chong Zhang Display display = choosePresentationDisplay(); 19345830b0b33618940d65197cec99d697b21908fec8Chong Zhang if (mPresentationDisplay != display) { 19355830b0b33618940d65197cec99d697b21908fec8Chong Zhang mPresentationDisplay = display; 19365830b0b33618940d65197cec99d697b21908fec8Chong Zhang return true; 19375830b0b33618940d65197cec99d697b21908fec8Chong Zhang } 19385830b0b33618940d65197cec99d697b21908fec8Chong Zhang return false; 19395830b0b33618940d65197cec99d697b21908fec8Chong Zhang } 19405830b0b33618940d65197cec99d697b21908fec8Chong Zhang 19415830b0b33618940d65197cec99d697b21908fec8Chong Zhang private Display choosePresentationDisplay() { 19425830b0b33618940d65197cec99d697b21908fec8Chong Zhang if ((mSupportedTypes & ROUTE_TYPE_LIVE_VIDEO) != 0) { 19435830b0b33618940d65197cec99d697b21908fec8Chong Zhang Display[] displays = sStatic.getAllPresentationDisplays(); 19445830b0b33618940d65197cec99d697b21908fec8Chong Zhang 19455830b0b33618940d65197cec99d697b21908fec8Chong Zhang // Ensure that the specified display is valid for presentations. 19465830b0b33618940d65197cec99d697b21908fec8Chong Zhang // This check will normally disallow the default display unless it was 19475830b0b33618940d65197cec99d697b21908fec8Chong Zhang // configured as a presentation display for some reason. 19485830b0b33618940d65197cec99d697b21908fec8Chong Zhang if (mPresentationDisplayId >= 0) { 19495830b0b33618940d65197cec99d697b21908fec8Chong Zhang for (Display display : displays) { 19505830b0b33618940d65197cec99d697b21908fec8Chong Zhang if (display.getDisplayId() == mPresentationDisplayId) { 19515830b0b33618940d65197cec99d697b21908fec8Chong Zhang return display; 19525830b0b33618940d65197cec99d697b21908fec8Chong Zhang } 19535830b0b33618940d65197cec99d697b21908fec8Chong Zhang } 19545830b0b33618940d65197cec99d697b21908fec8Chong Zhang return null; 19555830b0b33618940d65197cec99d697b21908fec8Chong Zhang } 19565830b0b33618940d65197cec99d697b21908fec8Chong Zhang 19575830b0b33618940d65197cec99d697b21908fec8Chong Zhang // Find the indicated Wifi display by its address. 19585830b0b33618940d65197cec99d697b21908fec8Chong Zhang if (mDeviceAddress != null) { 19595830b0b33618940d65197cec99d697b21908fec8Chong Zhang for (Display display : displays) { 19605830b0b33618940d65197cec99d697b21908fec8Chong Zhang if (display.getType() == Display.TYPE_WIFI 19615830b0b33618940d65197cec99d697b21908fec8Chong Zhang && mDeviceAddress.equals(display.getAddress())) { 19625830b0b33618940d65197cec99d697b21908fec8Chong Zhang return display; 19635830b0b33618940d65197cec99d697b21908fec8Chong Zhang } 19645830b0b33618940d65197cec99d697b21908fec8Chong Zhang } 19655830b0b33618940d65197cec99d697b21908fec8Chong Zhang return null; 19665830b0b33618940d65197cec99d697b21908fec8Chong Zhang } 19675830b0b33618940d65197cec99d697b21908fec8Chong Zhang 19685830b0b33618940d65197cec99d697b21908fec8Chong Zhang // For the default route, choose the first presentation display from the list. 19695830b0b33618940d65197cec99d697b21908fec8Chong Zhang if (this == sStatic.mDefaultAudioVideo && displays.length > 0) { 19705830b0b33618940d65197cec99d697b21908fec8Chong Zhang return displays[0]; 19715830b0b33618940d65197cec99d697b21908fec8Chong Zhang } 19725830b0b33618940d65197cec99d697b21908fec8Chong Zhang } 19735830b0b33618940d65197cec99d697b21908fec8Chong Zhang return null; 19745830b0b33618940d65197cec99d697b21908fec8Chong Zhang } 19755830b0b33618940d65197cec99d697b21908fec8Chong Zhang 197675af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown /** @hide */ 197775af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown public String getDeviceAddress() { 197875af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown return mDeviceAddress; 197975af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown } 198075af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown 198192130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown /** 1982a27b8fb4296c1271ddf5916843ddffda6764e65fJeff Brown * Returns true if this route is enabled and may be selected. 1983a27b8fb4296c1271ddf5916843ddffda6764e65fJeff Brown * 1984a27b8fb4296c1271ddf5916843ddffda6764e65fJeff Brown * @return True if this route is enabled. 1985705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell */ 1986705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell public boolean isEnabled() { 1987705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell return mEnabled; 1988705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1989705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 1990a27b8fb4296c1271ddf5916843ddffda6764e65fJeff Brown /** 1991a27b8fb4296c1271ddf5916843ddffda6764e65fJeff Brown * Returns true if the route is in the process of connecting and is not 1992a27b8fb4296c1271ddf5916843ddffda6764e65fJeff Brown * yet ready for use. 1993a27b8fb4296c1271ddf5916843ddffda6764e65fJeff Brown * 1994a27b8fb4296c1271ddf5916843ddffda6764e65fJeff Brown * @return True if this route is in the process of connecting. 1995a27b8fb4296c1271ddf5916843ddffda6764e65fJeff Brown */ 1996a27b8fb4296c1271ddf5916843ddffda6764e65fJeff Brown public boolean isConnecting() { 199739ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown return mResolvedStatusCode == STATUS_CONNECTING; 19980abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown } 19990abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown 20000abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown /** @hide */ 20010abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown public boolean isSelected() { 20020abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown return this == sStatic.mSelectedRoute; 20030abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown } 20040abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown 20050abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown /** @hide */ 20060abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown public boolean isDefault() { 20070abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown return this == sStatic.mDefaultAudioVideo; 20080abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown } 20090abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown 20100abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown /** @hide */ 20110abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown public void select() { 20120abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown selectRouteStatic(mSupportedTypes, this, true); 2013a27b8fb4296c1271ddf5916843ddffda6764e65fJeff Brown } 2014a27b8fb4296c1271ddf5916843ddffda6764e65fJeff Brown 20159a1de308cea2d160778fd977825f10a07b49d738Adam Powell void setStatusInt(CharSequence status) { 20169a1de308cea2d160778fd977825f10a07b49d738Adam Powell if (!status.equals(mStatus)) { 20179a1de308cea2d160778fd977825f10a07b49d738Adam Powell mStatus = status; 20189a1de308cea2d160778fd977825f10a07b49d738Adam Powell if (mGroup != null) { 20199a1de308cea2d160778fd977825f10a07b49d738Adam Powell mGroup.memberStatusChanged(this, status); 20209a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 20219a1de308cea2d160778fd977825f10a07b49d738Adam Powell routeUpdated(); 20229a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 20239a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 20249a1de308cea2d160778fd977825f10a07b49d738Adam Powell 20251357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi final IRemoteVolumeObserver.Stub mRemoteVolObserver = new IRemoteVolumeObserver.Stub() { 202669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown @Override 20271357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public void dispatchRemoteVolumeUpdate(final int direction, final int value) { 20281357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi sStatic.mHandler.post(new Runnable() { 20291357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi @Override 20301357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public void run() { 20311357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi if (mVcb != null) { 20321357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi if (direction != 0) { 20331357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi mVcb.vcb.onVolumeUpdateRequest(mVcb.route, direction); 20341357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } else { 20351357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi mVcb.vcb.onVolumeSetRequest(mVcb.route, value); 20361357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 20371357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 20381357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 20391357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi }); 20401357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 20411357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi }; 20421357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 20439a1de308cea2d160778fd977825f10a07b49d738Adam Powell void routeUpdated() { 20449a1de308cea2d160778fd977825f10a07b49d738Adam Powell updateRoute(this); 20459a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 20469a1de308cea2d160778fd977825f10a07b49d738Adam Powell 20479a1de308cea2d160778fd977825f10a07b49d738Adam Powell @Override 20489a1de308cea2d160778fd977825f10a07b49d738Adam Powell public String toString() { 2049d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell String supportedTypes = typesToString(getSupportedTypes()); 205092130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown return getClass().getSimpleName() + "{ name=" + getName() + 205156d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown ", description=" + getDescription() + 205292130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown ", status=" + getStatus() + 205392130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown ", category=" + getCategory() + 205492130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown ", supportedTypes=" + supportedTypes + 205569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown ", presentationDisplay=" + mPresentationDisplay + " }"; 20569a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 20579a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 20589a1de308cea2d160778fd977825f10a07b49d738Adam Powell 20599a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 20609a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Information about a route that the application may define and modify. 20618e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * A user route defaults to {@link RouteInfo#PLAYBACK_TYPE_REMOTE} and 20628e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * {@link RouteInfo#PLAYBACK_VOLUME_FIXED}. 20639a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 20649a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @see MediaRouter.RouteInfo 20659a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 2066b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn public static class UserRouteInfo extends RouteInfo { 2067ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell RemoteControlClient mRcc; 20685d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik SessionVolumeProvider mSvp; 20699a1de308cea2d160778fd977825f10a07b49d738Adam Powell 20709a1de308cea2d160778fd977825f10a07b49d738Adam Powell UserRouteInfo(RouteCategory category) { 20719a1de308cea2d160778fd977825f10a07b49d738Adam Powell super(category); 20729a1de308cea2d160778fd977825f10a07b49d738Adam Powell mSupportedTypes = ROUTE_TYPE_USER; 20738e37a85bf3dc39519942698dc90a3951306b934bAdam Powell mPlaybackType = PLAYBACK_TYPE_REMOTE; 20748e37a85bf3dc39519942698dc90a3951306b934bAdam Powell mVolumeHandling = PLAYBACK_VOLUME_FIXED; 20759a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 20769a1de308cea2d160778fd977825f10a07b49d738Adam Powell 20779a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 20789a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Set the user-visible name of this route. 20799a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param name Name to display to the user to describe this route 20809a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 20819a1de308cea2d160778fd977825f10a07b49d738Adam Powell public void setName(CharSequence name) { 20829a1de308cea2d160778fd977825f10a07b49d738Adam Powell mName = name; 20839a1de308cea2d160778fd977825f10a07b49d738Adam Powell routeUpdated(); 20849a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 20855d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik 20860d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell /** 20870d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * Set the user-visible name of this route. 208856d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * <p> 208956d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * The route name identifies the destination represented by the route. 209056d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * It may be a user-supplied name, an alias, or device serial number. 209156d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * </p> 209256d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * 20930d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * @param resId Resource ID of the name to display to the user to describe this route 20940d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell */ 20950d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public void setName(int resId) { 20960d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell mNameResId = resId; 20970d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell mName = null; 20980d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell routeUpdated(); 20990d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell } 21009a1de308cea2d160778fd977825f10a07b49d738Adam Powell 21019a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 210256d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * Set the user-visible description of this route. 210356d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * <p> 210456d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * The route description describes the kind of destination represented by the route. 210556d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * It may be a user-supplied string, a model number or brand of device. 210656d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * </p> 210756d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * 210856d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * @param description The description of the route, or null if none. 210956d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown */ 211056d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown public void setDescription(CharSequence description) { 211156d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown mDescription = description; 211256d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown routeUpdated(); 211356d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown } 211456d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown 211556d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown /** 21169a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Set the current user-visible status for this route. 21179a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param status Status to display to the user to describe what the endpoint 21189a1de308cea2d160778fd977825f10a07b49d738Adam Powell * of this route is currently doing 21199a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 21209a1de308cea2d160778fd977825f10a07b49d738Adam Powell public void setStatus(CharSequence status) { 21219a1de308cea2d160778fd977825f10a07b49d738Adam Powell setStatusInt(status); 21229a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 2123ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell 2124ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell /** 2125ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * Set the RemoteControlClient responsible for reporting playback info for this 2126ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * user route. 2127ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * 2128ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * <p>If this route manages remote playback, the data exposed by this 2129ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * RemoteControlClient will be used to reflect and update information 2130ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * such as route volume info in related UIs.</p> 2131ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * 21321357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * <p>The RemoteControlClient must have been previously registered with 21331357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * {@link AudioManager#registerRemoteControlClient(RemoteControlClient)}.</p> 21341357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * 2135ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * @param rcc RemoteControlClient associated with this route 2136ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell */ 2137ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell public void setRemoteControlClient(RemoteControlClient rcc) { 2138ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell mRcc = rcc; 21391357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi updatePlaybackInfoOnRcc(); 2140ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell } 2141ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell 2142ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell /** 21434599696591f745b3a546197d2ba7e5cfc5562484Adam Powell * Retrieve the RemoteControlClient associated with this route, if one has been set. 21444599696591f745b3a546197d2ba7e5cfc5562484Adam Powell * 21454599696591f745b3a546197d2ba7e5cfc5562484Adam Powell * @return the RemoteControlClient associated with this route 21464599696591f745b3a546197d2ba7e5cfc5562484Adam Powell * @see #setRemoteControlClient(RemoteControlClient) 21474599696591f745b3a546197d2ba7e5cfc5562484Adam Powell */ 21484599696591f745b3a546197d2ba7e5cfc5562484Adam Powell public RemoteControlClient getRemoteControlClient() { 21494599696591f745b3a546197d2ba7e5cfc5562484Adam Powell return mRcc; 21504599696591f745b3a546197d2ba7e5cfc5562484Adam Powell } 21514599696591f745b3a546197d2ba7e5cfc5562484Adam Powell 21524599696591f745b3a546197d2ba7e5cfc5562484Adam Powell /** 2153ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * Set an icon that will be used to represent this route. 2154ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * The system may use this icon in picker UIs or similar. 2155ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * 2156ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * @param icon icon drawable to use to represent this route 2157ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell */ 2158ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell public void setIconDrawable(Drawable icon) { 2159ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell mIcon = icon; 2160ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell } 2161ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell 2162ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell /** 2163ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * Set an icon that will be used to represent this route. 2164ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * The system may use this icon in picker UIs or similar. 2165ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * 216671c69897ad0a55d590698bfa399bfe99c763b9dbAdam Powell * @param resId Resource ID of an icon drawable to use to represent this route 2167ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell */ 21687b9c912f536925ac6ec43935d6e97506851b33d6Tor Norbye public void setIconResource(@DrawableRes int resId) { 2169ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell setIconDrawable(sStatic.mResources.getDrawable(resId)); 2170ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell } 21711357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 21721357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 21731357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * Set a callback to be notified of volume update requests 21741357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @param vcb 21751357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 21761357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public void setVolumeCallback(VolumeCallback vcb) { 21771357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi mVcb = new VolumeCallbackInfo(vcb, this); 21781357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 21791357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 21801357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 21811357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * Defines whether playback associated with this route is "local" 21821357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * ({@link RouteInfo#PLAYBACK_TYPE_LOCAL}) or "remote" 21831357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * ({@link RouteInfo#PLAYBACK_TYPE_REMOTE}). 21841357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @param type 21851357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 21867c090d54e2c0eb5309d3f7dc131e137d9c986793Insun Kang public void setPlaybackType(@RouteInfo.PlaybackType int type) { 21871357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi if (mPlaybackType != type) { 21881357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi mPlaybackType = type; 2189430fc48865e5a371b08f180390946b96d73848feRoboErik configureSessionVolume(); 21901357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 21911357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 21921357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 21931357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 21941357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * Defines whether volume for the playback associated with this route is fixed 21951357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * ({@link RouteInfo#PLAYBACK_VOLUME_FIXED}) or can modified 21961357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * ({@link RouteInfo#PLAYBACK_VOLUME_VARIABLE}). 21971357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @param volumeHandling 21981357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 21997c090d54e2c0eb5309d3f7dc131e137d9c986793Insun Kang public void setVolumeHandling(@RouteInfo.PlaybackVolume int volumeHandling) { 22001357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi if (mVolumeHandling != volumeHandling) { 22011357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi mVolumeHandling = volumeHandling; 2202430fc48865e5a371b08f180390946b96d73848feRoboErik configureSessionVolume(); 22031357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 22041357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 22051357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 22061357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 22071357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * Defines at what volume the playback associated with this route is performed (for user 22081357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * feedback purposes). This information is only used when the playback is not local. 22091357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @param volume 22101357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 22111357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public void setVolume(int volume) { 22128e37a85bf3dc39519942698dc90a3951306b934bAdam Powell volume = Math.max(0, Math.min(volume, getVolumeMax())); 22131357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi if (mVolume != volume) { 22141357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi mVolume = volume; 2215430fc48865e5a371b08f180390946b96d73848feRoboErik if (mSvp != null) { 22160d0f67f5ee5f939a1b611bc4583212707afd9beeRoboErik mSvp.setCurrentVolume(mVolume); 22175d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik } 22188e37a85bf3dc39519942698dc90a3951306b934bAdam Powell dispatchRouteVolumeChanged(this); 2219f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell if (mGroup != null) { 2220f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell mGroup.memberVolumeChanged(this); 2221f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell } 22228e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 22238e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 22248e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 22258e37a85bf3dc39519942698dc90a3951306b934bAdam Powell @Override 22268e37a85bf3dc39519942698dc90a3951306b934bAdam Powell public void requestSetVolume(int volume) { 22278e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (mVolumeHandling == PLAYBACK_VOLUME_VARIABLE) { 22288e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (mVcb == null) { 22298e37a85bf3dc39519942698dc90a3951306b934bAdam Powell Log.e(TAG, "Cannot requestSetVolume on user route - no volume callback set"); 22308e37a85bf3dc39519942698dc90a3951306b934bAdam Powell return; 22318e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 22328e37a85bf3dc39519942698dc90a3951306b934bAdam Powell mVcb.vcb.onVolumeSetRequest(this, volume); 22338e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 22348e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 22358e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 22368e37a85bf3dc39519942698dc90a3951306b934bAdam Powell @Override 22378e37a85bf3dc39519942698dc90a3951306b934bAdam Powell public void requestUpdateVolume(int direction) { 22388e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (mVolumeHandling == PLAYBACK_VOLUME_VARIABLE) { 22398e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (mVcb == null) { 22408e37a85bf3dc39519942698dc90a3951306b934bAdam Powell Log.e(TAG, "Cannot requestChangeVolume on user route - no volumec callback set"); 22418e37a85bf3dc39519942698dc90a3951306b934bAdam Powell return; 22428e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 22438e37a85bf3dc39519942698dc90a3951306b934bAdam Powell mVcb.vcb.onVolumeUpdateRequest(this, direction); 22441357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 22451357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 22461357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 22471357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 22481357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * Defines the maximum volume at which the playback associated with this route is performed 22491357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * (for user feedback purposes). This information is only used when the playback is not 22501357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * local. 22511357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @param volumeMax 22521357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 22531357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public void setVolumeMax(int volumeMax) { 22541357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi if (mVolumeMax != volumeMax) { 22551357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi mVolumeMax = volumeMax; 2256430fc48865e5a371b08f180390946b96d73848feRoboErik configureSessionVolume(); 22571357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 22581357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 22591357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 22601357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 22611357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * Defines over what stream type the media is presented. 22621357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @param stream 22631357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 22641357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public void setPlaybackStream(int stream) { 22651357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi if (mPlaybackStream != stream) { 22661357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi mPlaybackStream = stream; 2267430fc48865e5a371b08f180390946b96d73848feRoboErik configureSessionVolume(); 22681357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 22691357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 22701357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 22711357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi private void updatePlaybackInfoOnRcc() { 2272430fc48865e5a371b08f180390946b96d73848feRoboErik configureSessionVolume(); 22735d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik } 22745d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik 22755d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik private void configureSessionVolume() { 22765d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik if (mRcc == null) { 22775d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik if (DEBUG) { 22785d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik Log.d(TAG, "No Rcc to configure volume for route " + mName); 22795d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik } 22805d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik return; 22815d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik } 22825d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik MediaSession session = mRcc.getMediaSession(); 22835d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik if (session == null) { 22845d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik if (DEBUG) { 22855d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik Log.d(TAG, "Rcc has no session to configure volume"); 22865d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik } 22875d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik return; 22885d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik } 22895d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik if (mPlaybackType == RemoteControlClient.PLAYBACK_TYPE_REMOTE) { 22907c090d54e2c0eb5309d3f7dc131e137d9c986793Insun Kang @VolumeProvider.ControlType int volumeControl = 22917c090d54e2c0eb5309d3f7dc131e137d9c986793Insun Kang VolumeProvider.VOLUME_CONTROL_FIXED; 22925d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik switch (mVolumeHandling) { 22935d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik case RemoteControlClient.PLAYBACK_VOLUME_VARIABLE: 2294ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik volumeControl = VolumeProvider.VOLUME_CONTROL_ABSOLUTE; 22955d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik break; 22965d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik case RemoteControlClient.PLAYBACK_VOLUME_FIXED: 22975d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik default: 22985d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik break; 22991357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 23005d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik // Only register a new listener if necessary 23015d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik if (mSvp == null || mSvp.getVolumeControl() != volumeControl 23025d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik || mSvp.getMaxVolume() != mVolumeMax) { 23030d0f67f5ee5f939a1b611bc4583212707afd9beeRoboErik mSvp = new SessionVolumeProvider(volumeControl, mVolumeMax, mVolume); 23045d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik session.setPlaybackToRemote(mSvp); 23055d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik } 23065d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik } else { 23075d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik // We only know how to handle local and remote, fall back to local if not remote. 23089db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik AudioAttributes.Builder bob = new AudioAttributes.Builder(); 23099db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik bob.setLegacyStreamType(mPlaybackStream); 23109db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik session.setPlaybackToLocal(bob.build()); 23115d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik mSvp = null; 23121357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 23131357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 23141357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 2315ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik class SessionVolumeProvider extends VolumeProvider { 23165d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik 23177c090d54e2c0eb5309d3f7dc131e137d9c986793Insun Kang public SessionVolumeProvider(@VolumeProvider.ControlType int volumeControl, 23187c090d54e2c0eb5309d3f7dc131e137d9c986793Insun Kang int maxVolume, int currentVolume) { 23190d0f67f5ee5f939a1b611bc4583212707afd9beeRoboErik super(volumeControl, maxVolume, currentVolume); 23205d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik } 23215d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik 23225d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik @Override 23235d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik public void onSetVolumeTo(final int volume) { 23245d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik sStatic.mHandler.post(new Runnable() { 23255d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik @Override 23265d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik public void run() { 23275d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik if (mVcb != null) { 23285d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik mVcb.vcb.onVolumeSetRequest(mVcb.route, volume); 23295d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik } 23305d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik } 23315d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik }); 23325d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik } 23335d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik 23345d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik @Override 23351ff5b1648a051e9650614f0c0f1b3f449777db81RoboErik public void onAdjustVolume(final int direction) { 23365d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik sStatic.mHandler.post(new Runnable() { 23375d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik @Override 23385d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik public void run() { 23395d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik if (mVcb != null) { 23401ff5b1648a051e9650614f0c0f1b3f449777db81RoboErik mVcb.vcb.onVolumeUpdateRequest(mVcb.route, direction); 23415d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik } 23425d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik } 23435d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik }); 23445d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik } 23455d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik } 23469a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 23479a1de308cea2d160778fd977825f10a07b49d738Adam Powell 23489a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 23499a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Information about a route that consists of multiple other routes in a group. 23509a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 2351b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn public static class RouteGroup extends RouteInfo { 23529a1de308cea2d160778fd977825f10a07b49d738Adam Powell final ArrayList<RouteInfo> mRoutes = new ArrayList<RouteInfo>(); 23539a1de308cea2d160778fd977825f10a07b49d738Adam Powell private boolean mUpdateName; 23549a1de308cea2d160778fd977825f10a07b49d738Adam Powell 23559a1de308cea2d160778fd977825f10a07b49d738Adam Powell RouteGroup(RouteCategory category) { 23569a1de308cea2d160778fd977825f10a07b49d738Adam Powell super(category); 23579a1de308cea2d160778fd977825f10a07b49d738Adam Powell mGroup = this; 23588e37a85bf3dc39519942698dc90a3951306b934bAdam Powell mVolumeHandling = PLAYBACK_VOLUME_FIXED; 23599a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 23609a1de308cea2d160778fd977825f10a07b49d738Adam Powell 236169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown @Override 23620d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell CharSequence getName(Resources res) { 23639a1de308cea2d160778fd977825f10a07b49d738Adam Powell if (mUpdateName) updateName(); 23640d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell return super.getName(res); 23659a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 23669a1de308cea2d160778fd977825f10a07b49d738Adam Powell 23679a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 23689a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Add a route to this group. The route must not currently belong to another group. 23699a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 23709a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param route route to add to this group 23719a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 23729a1de308cea2d160778fd977825f10a07b49d738Adam Powell public void addRoute(RouteInfo route) { 23739a1de308cea2d160778fd977825f10a07b49d738Adam Powell if (route.getGroup() != null) { 23749a1de308cea2d160778fd977825f10a07b49d738Adam Powell throw new IllegalStateException("Route " + route + " is already part of a group."); 23759a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 23769a1de308cea2d160778fd977825f10a07b49d738Adam Powell if (route.getCategory() != mCategory) { 23779a1de308cea2d160778fd977825f10a07b49d738Adam Powell throw new IllegalArgumentException( 23789a1de308cea2d160778fd977825f10a07b49d738Adam Powell "Route cannot be added to a group with a different category. " + 23799a1de308cea2d160778fd977825f10a07b49d738Adam Powell "(Route category=" + route.getCategory() + 23809a1de308cea2d160778fd977825f10a07b49d738Adam Powell " group category=" + mCategory + ")"); 23819a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 2382d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell final int at = mRoutes.size(); 23839a1de308cea2d160778fd977825f10a07b49d738Adam Powell mRoutes.add(route); 2384d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell route.mGroup = this; 23859a1de308cea2d160778fd977825f10a07b49d738Adam Powell mUpdateName = true; 2386f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell updateVolume(); 23879a1de308cea2d160778fd977825f10a07b49d738Adam Powell routeUpdated(); 2388f3b653a21cdffe04c94c275e69ecb56e00766e82Adam Powell dispatchRouteGrouped(route, this, at); 23899a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 23909a1de308cea2d160778fd977825f10a07b49d738Adam Powell 23919a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 23929a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Add a route to this group before the specified index. 23939a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 23949a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param route route to add 23959a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param insertAt insert the new route before this index 23969a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 23979a1de308cea2d160778fd977825f10a07b49d738Adam Powell public void addRoute(RouteInfo route, int insertAt) { 23989a1de308cea2d160778fd977825f10a07b49d738Adam Powell if (route.getGroup() != null) { 23999a1de308cea2d160778fd977825f10a07b49d738Adam Powell throw new IllegalStateException("Route " + route + " is already part of a group."); 24009a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 24019a1de308cea2d160778fd977825f10a07b49d738Adam Powell if (route.getCategory() != mCategory) { 24029a1de308cea2d160778fd977825f10a07b49d738Adam Powell throw new IllegalArgumentException( 24039a1de308cea2d160778fd977825f10a07b49d738Adam Powell "Route cannot be added to a group with a different category. " + 24049a1de308cea2d160778fd977825f10a07b49d738Adam Powell "(Route category=" + route.getCategory() + 24059a1de308cea2d160778fd977825f10a07b49d738Adam Powell " group category=" + mCategory + ")"); 24069a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 24079a1de308cea2d160778fd977825f10a07b49d738Adam Powell mRoutes.add(insertAt, route); 2408d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell route.mGroup = this; 24099a1de308cea2d160778fd977825f10a07b49d738Adam Powell mUpdateName = true; 2410f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell updateVolume(); 24119a1de308cea2d160778fd977825f10a07b49d738Adam Powell routeUpdated(); 2412f3b653a21cdffe04c94c275e69ecb56e00766e82Adam Powell dispatchRouteGrouped(route, this, insertAt); 24139a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 24149a1de308cea2d160778fd977825f10a07b49d738Adam Powell 24159a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 24169a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Remove a route from this group. 24179a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 24189a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param route route to remove 24199a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 24209a1de308cea2d160778fd977825f10a07b49d738Adam Powell public void removeRoute(RouteInfo route) { 24219a1de308cea2d160778fd977825f10a07b49d738Adam Powell if (route.getGroup() != this) { 24229a1de308cea2d160778fd977825f10a07b49d738Adam Powell throw new IllegalArgumentException("Route " + route + 24239a1de308cea2d160778fd977825f10a07b49d738Adam Powell " is not a member of this group."); 24249a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 24259a1de308cea2d160778fd977825f10a07b49d738Adam Powell mRoutes.remove(route); 2426d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell route.mGroup = null; 24279a1de308cea2d160778fd977825f10a07b49d738Adam Powell mUpdateName = true; 2428f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell updateVolume(); 2429d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell dispatchRouteUngrouped(route, this); 24309a1de308cea2d160778fd977825f10a07b49d738Adam Powell routeUpdated(); 24319a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 24329a1de308cea2d160778fd977825f10a07b49d738Adam Powell 24339a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 24349a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Remove the route at the specified index from this group. 24359a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 24369a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param index index of the route to remove 24379a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 24389a1de308cea2d160778fd977825f10a07b49d738Adam Powell public void removeRoute(int index) { 2439d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell RouteInfo route = mRoutes.remove(index); 2440d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell route.mGroup = null; 24419a1de308cea2d160778fd977825f10a07b49d738Adam Powell mUpdateName = true; 2442f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell updateVolume(); 2443d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell dispatchRouteUngrouped(route, this); 24449a1de308cea2d160778fd977825f10a07b49d738Adam Powell routeUpdated(); 24459a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 24469a1de308cea2d160778fd977825f10a07b49d738Adam Powell 2447d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell /** 2448d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @return The number of routes in this group 2449d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell */ 2450d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell public int getRouteCount() { 2451d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell return mRoutes.size(); 2452d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell } 2453d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell 2454d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell /** 2455d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * Return the route in this group at the specified index 2456d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * 2457d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param index Index to fetch 2458d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @return The route at index 2459d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell */ 2460d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell public RouteInfo getRouteAt(int index) { 2461d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell return mRoutes.get(index); 2462d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell } 2463d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell 2464ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell /** 2465ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * Set an icon that will be used to represent this group. 2466ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * The system may use this icon in picker UIs or similar. 2467ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * 2468ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * @param icon icon drawable to use to represent this group 2469ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell */ 2470ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell public void setIconDrawable(Drawable icon) { 2471ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell mIcon = icon; 2472ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell } 2473ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell 2474ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell /** 2475ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * Set an icon that will be used to represent this group. 2476ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * The system may use this icon in picker UIs or similar. 2477ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * 247871c69897ad0a55d590698bfa399bfe99c763b9dbAdam Powell * @param resId Resource ID of an icon drawable to use to represent this group 2479ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell */ 24807b9c912f536925ac6ec43935d6e97506851b33d6Tor Norbye public void setIconResource(@DrawableRes int resId) { 2481ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell setIconDrawable(sStatic.mResources.getDrawable(resId)); 2482ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell } 2483ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell 24848e37a85bf3dc39519942698dc90a3951306b934bAdam Powell @Override 24858e37a85bf3dc39519942698dc90a3951306b934bAdam Powell public void requestSetVolume(int volume) { 24868e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final int maxVol = getVolumeMax(); 24878e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (maxVol == 0) { 24888e37a85bf3dc39519942698dc90a3951306b934bAdam Powell return; 24898e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 24908e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 24918e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final float scaledVolume = (float) volume / maxVol; 24928e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final int routeCount = getRouteCount(); 24938e37a85bf3dc39519942698dc90a3951306b934bAdam Powell for (int i = 0; i < routeCount; i++) { 24948e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final RouteInfo route = getRouteAt(i); 24958e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final int routeVol = (int) (scaledVolume * route.getVolumeMax()); 24968e37a85bf3dc39519942698dc90a3951306b934bAdam Powell route.requestSetVolume(routeVol); 24978e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 24988e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (volume != mVolume) { 24998e37a85bf3dc39519942698dc90a3951306b934bAdam Powell mVolume = volume; 25008e37a85bf3dc39519942698dc90a3951306b934bAdam Powell dispatchRouteVolumeChanged(this); 25018e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 25028e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 25038e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 25048e37a85bf3dc39519942698dc90a3951306b934bAdam Powell @Override 25058e37a85bf3dc39519942698dc90a3951306b934bAdam Powell public void requestUpdateVolume(int direction) { 25068e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final int maxVol = getVolumeMax(); 25078e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (maxVol == 0) { 25088e37a85bf3dc39519942698dc90a3951306b934bAdam Powell return; 25098e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 25108e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 25118e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final int routeCount = getRouteCount(); 2512f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell int volume = 0; 25138e37a85bf3dc39519942698dc90a3951306b934bAdam Powell for (int i = 0; i < routeCount; i++) { 25148e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final RouteInfo route = getRouteAt(i); 25158e37a85bf3dc39519942698dc90a3951306b934bAdam Powell route.requestUpdateVolume(direction); 2516f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell final int routeVol = route.getVolume(); 2517f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell if (routeVol > volume) { 2518f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell volume = routeVol; 2519f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell } 25208e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 25218e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (volume != mVolume) { 25228e37a85bf3dc39519942698dc90a3951306b934bAdam Powell mVolume = volume; 25238e37a85bf3dc39519942698dc90a3951306b934bAdam Powell dispatchRouteVolumeChanged(this); 25248e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 25258e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 25268e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 25279a1de308cea2d160778fd977825f10a07b49d738Adam Powell void memberNameChanged(RouteInfo info, CharSequence name) { 25289a1de308cea2d160778fd977825f10a07b49d738Adam Powell mUpdateName = true; 25299a1de308cea2d160778fd977825f10a07b49d738Adam Powell routeUpdated(); 25309a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 25319a1de308cea2d160778fd977825f10a07b49d738Adam Powell 25329a1de308cea2d160778fd977825f10a07b49d738Adam Powell void memberStatusChanged(RouteInfo info, CharSequence status) { 25339a1de308cea2d160778fd977825f10a07b49d738Adam Powell setStatusInt(status); 25349a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 25359a1de308cea2d160778fd977825f10a07b49d738Adam Powell 2536f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell void memberVolumeChanged(RouteInfo info) { 2537f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell updateVolume(); 2538f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell } 2539f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell 2540f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell void updateVolume() { 2541f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell // A group always represents the highest component volume value. 2542f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell final int routeCount = getRouteCount(); 2543f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell int volume = 0; 2544f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell for (int i = 0; i < routeCount; i++) { 2545f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell final int routeVol = getRouteAt(i).getVolume(); 2546f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell if (routeVol > volume) { 2547f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell volume = routeVol; 2548f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell } 2549f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell } 2550f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell if (volume != mVolume) { 2551f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell mVolume = volume; 2552f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell dispatchRouteVolumeChanged(this); 2553f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell } 2554f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell } 2555f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell 2556d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell @Override 2557d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell void routeUpdated() { 2558d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell int types = 0; 2559d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell final int count = mRoutes.size(); 2560b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell if (count == 0) { 2561b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell // Don't keep empty groups in the router. 256269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown MediaRouter.removeRouteStatic(this); 2563b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell return; 2564b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell } 2565b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell 25668e37a85bf3dc39519942698dc90a3951306b934bAdam Powell int maxVolume = 0; 25678e37a85bf3dc39519942698dc90a3951306b934bAdam Powell boolean isLocal = true; 25688e37a85bf3dc39519942698dc90a3951306b934bAdam Powell boolean isFixedVolume = true; 2569d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell for (int i = 0; i < count; i++) { 25708e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final RouteInfo route = mRoutes.get(i); 25718e37a85bf3dc39519942698dc90a3951306b934bAdam Powell types |= route.mSupportedTypes; 25728e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final int routeMaxVolume = route.getVolumeMax(); 25738e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (routeMaxVolume > maxVolume) { 25748e37a85bf3dc39519942698dc90a3951306b934bAdam Powell maxVolume = routeMaxVolume; 25758e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 25768e37a85bf3dc39519942698dc90a3951306b934bAdam Powell isLocal &= route.getPlaybackType() == PLAYBACK_TYPE_LOCAL; 25778e37a85bf3dc39519942698dc90a3951306b934bAdam Powell isFixedVolume &= route.getVolumeHandling() == PLAYBACK_VOLUME_FIXED; 2578d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell } 25798e37a85bf3dc39519942698dc90a3951306b934bAdam Powell mPlaybackType = isLocal ? PLAYBACK_TYPE_LOCAL : PLAYBACK_TYPE_REMOTE; 25808e37a85bf3dc39519942698dc90a3951306b934bAdam Powell mVolumeHandling = isFixedVolume ? PLAYBACK_VOLUME_FIXED : PLAYBACK_VOLUME_VARIABLE; 2581d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell mSupportedTypes = types; 25828e37a85bf3dc39519942698dc90a3951306b934bAdam Powell mVolumeMax = maxVolume; 2583d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell mIcon = count == 1 ? mRoutes.get(0).getIconDrawable() : null; 2584d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell super.routeUpdated(); 2585d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell } 2586d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell 25879a1de308cea2d160778fd977825f10a07b49d738Adam Powell void updateName() { 25889a1de308cea2d160778fd977825f10a07b49d738Adam Powell final StringBuilder sb = new StringBuilder(); 25899a1de308cea2d160778fd977825f10a07b49d738Adam Powell final int count = mRoutes.size(); 25909a1de308cea2d160778fd977825f10a07b49d738Adam Powell for (int i = 0; i < count; i++) { 25919a1de308cea2d160778fd977825f10a07b49d738Adam Powell final RouteInfo info = mRoutes.get(i); 2592b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell // TODO: There's probably a much more correct way to localize this. 25939a1de308cea2d160778fd977825f10a07b49d738Adam Powell if (i > 0) sb.append(", "); 25949a1de308cea2d160778fd977825f10a07b49d738Adam Powell sb.append(info.mName); 25959a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 25969a1de308cea2d160778fd977825f10a07b49d738Adam Powell mName = sb.toString(); 25979a1de308cea2d160778fd977825f10a07b49d738Adam Powell mUpdateName = false; 25989a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 2599d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell 2600d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell @Override 2601d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell public String toString() { 2602d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell StringBuilder sb = new StringBuilder(super.toString()); 2603d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell sb.append('['); 2604d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell final int count = mRoutes.size(); 2605d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell for (int i = 0; i < count; i++) { 2606d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell if (i > 0) sb.append(", "); 2607d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell sb.append(mRoutes.get(i)); 2608d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell } 2609d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell sb.append(']'); 2610d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell return sb.toString(); 2611d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell } 26129a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 26139a1de308cea2d160778fd977825f10a07b49d738Adam Powell 26149a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 26159a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Definition of a category of routes. All routes belong to a category. 26169a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 2617b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn public static class RouteCategory { 26189a1de308cea2d160778fd977825f10a07b49d738Adam Powell CharSequence mName; 26190d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell int mNameResId; 26209a1de308cea2d160778fd977825f10a07b49d738Adam Powell int mTypes; 26219a1de308cea2d160778fd977825f10a07b49d738Adam Powell final boolean mGroupable; 2622705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell boolean mIsSystem; 26239a1de308cea2d160778fd977825f10a07b49d738Adam Powell 26249a1de308cea2d160778fd977825f10a07b49d738Adam Powell RouteCategory(CharSequence name, int types, boolean groupable) { 26259a1de308cea2d160778fd977825f10a07b49d738Adam Powell mName = name; 26269a1de308cea2d160778fd977825f10a07b49d738Adam Powell mTypes = types; 26279a1de308cea2d160778fd977825f10a07b49d738Adam Powell mGroupable = groupable; 26289a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 26299a1de308cea2d160778fd977825f10a07b49d738Adam Powell 26300d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell RouteCategory(int nameResId, int types, boolean groupable) { 26310d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell mNameResId = nameResId; 26320d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell mTypes = types; 26330d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell mGroupable = groupable; 26340d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell } 26350d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell 26369a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 26379a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @return the name of this route category 26389a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 26399a1de308cea2d160778fd977825f10a07b49d738Adam Powell public CharSequence getName() { 26400d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell return getName(sStatic.mResources); 26410d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell } 26425d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik 26430d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell /** 26440d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * Return the properly localized/configuration dependent name of this RouteCategory. 26455d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik * 26460d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * @param context Context to resolve name resources 26470d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * @return the name of this route category 26480d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell */ 26490d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public CharSequence getName(Context context) { 26500d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell return getName(context.getResources()); 26510d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell } 26525d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik 26530d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell CharSequence getName(Resources res) { 26540d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell if (mNameResId != 0) { 26550d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell return res.getText(mNameResId); 26560d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell } 26579a1de308cea2d160778fd977825f10a07b49d738Adam Powell return mName; 26589a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 26599a1de308cea2d160778fd977825f10a07b49d738Adam Powell 26609a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 2661d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * Return the current list of routes in this category that have been added 2662d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * to the MediaRouter. 26639a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 2664d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * <p>This list will not include routes that are nested within RouteGroups. 2665d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * A RouteGroup is treated as a single route within its category.</p> 2666d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * 2667d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param out a List to fill with the routes in this category. If this parameter is 2668d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * non-null, it will be cleared, filled with the current routes with this 2669d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * category, and returned. If this parameter is null, a new List will be 2670d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * allocated to report the category's current routes. 2671d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @return A list with the routes in this category that have been added to the MediaRouter. 26729a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 2673d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell public List<RouteInfo> getRoutes(List<RouteInfo> out) { 2674d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell if (out == null) { 2675d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell out = new ArrayList<RouteInfo>(); 2676d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell } else { 2677d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell out.clear(); 2678d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell } 2679d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell 2680b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn final int count = getRouteCountStatic(); 2681d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell for (int i = 0; i < count; i++) { 2682b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn final RouteInfo route = getRouteAtStatic(i); 2683d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell if (route.mCategory == this) { 2684d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell out.add(route); 2685d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell } 2686d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell } 2687d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell return out; 26889a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 26899a1de308cea2d160778fd977825f10a07b49d738Adam Powell 26909a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 26919a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @return Flag set describing the route types supported by this category 26929a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 26939a1de308cea2d160778fd977825f10a07b49d738Adam Powell public int getSupportedTypes() { 26949a1de308cea2d160778fd977825f10a07b49d738Adam Powell return mTypes; 26959a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 26969a1de308cea2d160778fd977825f10a07b49d738Adam Powell 26979a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 26989a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Return whether or not this category supports grouping. 26999a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 27009a1de308cea2d160778fd977825f10a07b49d738Adam Powell * <p>If this method returns true, all routes obtained from this category 2701d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * via calls to {@link #getRouteAt(int)} will be {@link MediaRouter.RouteGroup}s.</p> 27029a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 27039a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @return true if this category supports 27049a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 27059a1de308cea2d160778fd977825f10a07b49d738Adam Powell public boolean isGroupable() { 27069a1de308cea2d160778fd977825f10a07b49d738Adam Powell return mGroupable; 27079a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 27089a1de308cea2d160778fd977825f10a07b49d738Adam Powell 2709705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell /** 2710705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell * @return true if this is the category reserved for system routes. 2711705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell * @hide 2712705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell */ 2713705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell public boolean isSystem() { 2714705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell return mIsSystem; 2715705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 2716705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 271769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown @Override 27189a1de308cea2d160778fd977825f10a07b49d738Adam Powell public String toString() { 27199a1de308cea2d160778fd977825f10a07b49d738Adam Powell return "RouteCategory{ name=" + mName + " types=" + typesToString(mTypes) + 2720d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell " groupable=" + mGroupable + " }"; 27219a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 27229a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 27239a1de308cea2d160778fd977825f10a07b49d738Adam Powell 27249a1de308cea2d160778fd977825f10a07b49d738Adam Powell static class CallbackInfo { 27259a1de308cea2d160778fd977825f10a07b49d738Adam Powell public int type; 272666f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown public int flags; 2727b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn public final Callback cb; 2728b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn public final MediaRouter router; 27299a1de308cea2d160778fd977825f10a07b49d738Adam Powell 273066f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown public CallbackInfo(Callback cb, int type, int flags, MediaRouter router) { 27319a1de308cea2d160778fd977825f10a07b49d738Adam Powell this.cb = cb; 27329a1de308cea2d160778fd977825f10a07b49d738Adam Powell this.type = type; 273366f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown this.flags = flags; 2734b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn this.router = router; 27359a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 273666f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown 273766f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown public boolean filterRouteEvent(RouteInfo route) { 2738af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown return filterRouteEvent(route.mSupportedTypes); 2739af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown } 2740af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown 2741af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown public boolean filterRouteEvent(int supportedTypes) { 274266f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown return (flags & CALLBACK_FLAG_UNFILTERED_EVENTS) != 0 2743af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown || (type & supportedTypes) != 0; 274466f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown } 27459a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 27469a1de308cea2d160778fd977825f10a07b49d738Adam Powell 27479a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 27489a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Interface for receiving events about media routing changes. 27499a1de308cea2d160778fd977825f10a07b49d738Adam Powell * All methods of this interface will be called from the application's main thread. 275066f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * <p> 275166f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * A Callback will only receive events relevant to routes that the callback 275266f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * was registered for unless the {@link MediaRouter#CALLBACK_FLAG_UNFILTERED_EVENTS} 275366f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * flag was specified in {@link MediaRouter#addCallback(int, Callback, int)}. 275466f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * </p> 27559a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 275666f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * @see MediaRouter#addCallback(int, Callback, int) 27579a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @see MediaRouter#removeCallback(Callback) 27589a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 27590d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public static abstract class Callback { 27609a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 27619a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Called when the supplied route becomes selected as the active route 27629a1de308cea2d160778fd977825f10a07b49d738Adam Powell * for the given route type. 27639a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 2764d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param router the MediaRouter reporting the event 27659a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param type Type flag set indicating the routes that have been selected 27669a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param info Route that has been selected for the given route types 27679a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 27680d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public abstract void onRouteSelected(MediaRouter router, int type, RouteInfo info); 27699a1de308cea2d160778fd977825f10a07b49d738Adam Powell 27709a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 27719a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Called when the supplied route becomes unselected as the active route 27729a1de308cea2d160778fd977825f10a07b49d738Adam Powell * for the given route type. 27739a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 2774d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param router the MediaRouter reporting the event 27759a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param type Type flag set indicating the routes that have been unselected 27769a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param info Route that has been unselected for the given route types 27779a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 27780d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public abstract void onRouteUnselected(MediaRouter router, int type, RouteInfo info); 27799a1de308cea2d160778fd977825f10a07b49d738Adam Powell 27809a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 27819a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Called when a route for the specified type was added. 27829a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 2783d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param router the MediaRouter reporting the event 27849a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param info Route that has become available for use 27859a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 27860d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public abstract void onRouteAdded(MediaRouter router, RouteInfo info); 27879a1de308cea2d160778fd977825f10a07b49d738Adam Powell 27889a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 27899a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Called when a route for the specified type was removed. 27909a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 2791d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param router the MediaRouter reporting the event 27929a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param info Route that has been removed from availability 27939a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 27940d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public abstract void onRouteRemoved(MediaRouter router, RouteInfo info); 27959a1de308cea2d160778fd977825f10a07b49d738Adam Powell 27969a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 27979a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Called when an aspect of the indicated route has changed. 27989a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 27999a1de308cea2d160778fd977825f10a07b49d738Adam Powell * <p>This will not indicate that the types supported by this route have 28009a1de308cea2d160778fd977825f10a07b49d738Adam Powell * changed, only that cosmetic info such as name or status have been updated.</p> 28019a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 2802d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param router the MediaRouter reporting the event 28039a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param info The route that was changed 28049a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 28050d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public abstract void onRouteChanged(MediaRouter router, RouteInfo info); 2806d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell 2807d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell /** 2808d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * Called when a route is added to a group. 2809d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * 2810d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param router the MediaRouter reporting the event 2811d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param info The route that was added 2812d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param group The group the route was added to 2813d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param index The route index within group that info was added at 2814d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell */ 28150d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public abstract void onRouteGrouped(MediaRouter router, RouteInfo info, RouteGroup group, 28160d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell int index); 2817d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell 2818d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell /** 2819d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * Called when a route is removed from a group. 2820d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * 2821d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param router the MediaRouter reporting the event 2822d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param info The route that was removed 2823d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param group The group the route was removed from 2824d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell */ 28250d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public abstract void onRouteUngrouped(MediaRouter router, RouteInfo info, RouteGroup group); 28268e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 28278e37a85bf3dc39519942698dc90a3951306b934bAdam Powell /** 28288e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * Called when a route's volume changes. 28298e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * 28308e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * @param router the MediaRouter reporting the event 28318e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * @param info The route with altered volume 28328e37a85bf3dc39519942698dc90a3951306b934bAdam Powell */ 28338e37a85bf3dc39519942698dc90a3951306b934bAdam Powell public abstract void onRouteVolumeChanged(MediaRouter router, RouteInfo info); 283492130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown 283592130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown /** 283692130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * Called when a route's presentation display changes. 283792130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * <p> 283892130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * This method is called whenever the route's presentation display becomes 283992130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * available, is removes or has changes to some of its properties (such as its size). 284092130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * </p> 284192130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * 284292130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * @param router the MediaRouter reporting the event 284392130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * @param info The route whose presentation display changed 284492130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * 284592130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * @see RouteInfo#getPresentationDisplay() 284692130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown */ 284792130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown public void onRoutePresentationDisplayChanged(MediaRouter router, RouteInfo info) { 284892130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown } 28499a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 28509a1de308cea2d160778fd977825f10a07b49d738Adam Powell 28519a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 28520d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * Stub implementation of {@link MediaRouter.Callback}. 28530d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * Each abstract method is defined as a no-op. Override just the ones 28549a1de308cea2d160778fd977825f10a07b49d738Adam Powell * you need. 28559a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 28560d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public static class SimpleCallback extends Callback { 28579a1de308cea2d160778fd977825f10a07b49d738Adam Powell 28589a1de308cea2d160778fd977825f10a07b49d738Adam Powell @Override 2859d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell public void onRouteSelected(MediaRouter router, int type, RouteInfo info) { 28609a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 28619a1de308cea2d160778fd977825f10a07b49d738Adam Powell 28629a1de308cea2d160778fd977825f10a07b49d738Adam Powell @Override 2863d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell public void onRouteUnselected(MediaRouter router, int type, RouteInfo info) { 28649a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 28659a1de308cea2d160778fd977825f10a07b49d738Adam Powell 28669a1de308cea2d160778fd977825f10a07b49d738Adam Powell @Override 2867d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell public void onRouteAdded(MediaRouter router, RouteInfo info) { 28689a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 28699a1de308cea2d160778fd977825f10a07b49d738Adam Powell 28709a1de308cea2d160778fd977825f10a07b49d738Adam Powell @Override 2871d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell public void onRouteRemoved(MediaRouter router, RouteInfo info) { 28729a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 28739a1de308cea2d160778fd977825f10a07b49d738Adam Powell 28749a1de308cea2d160778fd977825f10a07b49d738Adam Powell @Override 2875d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell public void onRouteChanged(MediaRouter router, RouteInfo info) { 28769a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 28779a1de308cea2d160778fd977825f10a07b49d738Adam Powell 28789a1de308cea2d160778fd977825f10a07b49d738Adam Powell @Override 2879d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell public void onRouteGrouped(MediaRouter router, RouteInfo info, RouteGroup group, 2880d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell int index) { 28819a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 28829a1de308cea2d160778fd977825f10a07b49d738Adam Powell 28839a1de308cea2d160778fd977825f10a07b49d738Adam Powell @Override 2884d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell public void onRouteUngrouped(MediaRouter router, RouteInfo info, RouteGroup group) { 28859a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 2886d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell 28878e37a85bf3dc39519942698dc90a3951306b934bAdam Powell @Override 28888e37a85bf3dc39519942698dc90a3951306b934bAdam Powell public void onRouteVolumeChanged(MediaRouter router, RouteInfo info) { 28898e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 28909a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 28911357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 28921357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi static class VolumeCallbackInfo { 28931357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public final VolumeCallback vcb; 28941357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public final RouteInfo route; 28951357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 28961357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public VolumeCallbackInfo(VolumeCallback vcb, RouteInfo route) { 28971357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi this.vcb = vcb; 28981357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi this.route = route; 28991357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 29001357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 29011357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 29021357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 29031357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * Interface for receiving events about volume changes. 29041357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * All methods of this interface will be called from the application's main thread. 29051357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * 29061357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * <p>A VolumeCallback will only receive events relevant to routes that the callback 29071357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * was registered for.</p> 29081357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * 29091357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @see UserRouteInfo#setVolumeCallback(VolumeCallback) 29101357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 29111357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public static abstract class VolumeCallback { 29121357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 29131357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * Called when the volume for the route should be increased or decreased. 29141357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @param info the route affected by this event 29151357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @param direction an integer indicating whether the volume is to be increased 29161357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * (positive value) or decreased (negative value). 29171357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * For bundled changes, the absolute value indicates the number of changes 29181357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * in the same direction, e.g. +3 corresponds to three "volume up" changes. 29191357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 29201357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public abstract void onVolumeUpdateRequest(RouteInfo info, int direction); 29211357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 29221357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * Called when the volume for the route should be set to the given value 29231357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @param info the route affected by this event 29241357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @param volume an integer indicating the new volume value that should be used, always 29251357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * between 0 and the value set by {@link UserRouteInfo#setVolumeMax(int)}. 29261357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 29271357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public abstract void onVolumeSetRequest(RouteInfo info, int volume); 29281357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 29291357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 29308e37a85bf3dc39519942698dc90a3951306b934bAdam Powell static class VolumeChangeReceiver extends BroadcastReceiver { 29318e37a85bf3dc39519942698dc90a3951306b934bAdam Powell @Override 29328e37a85bf3dc39519942698dc90a3951306b934bAdam Powell public void onReceive(Context context, Intent intent) { 29338e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (intent.getAction().equals(AudioManager.VOLUME_CHANGED_ACTION)) { 29348e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final int streamType = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, 29358e37a85bf3dc39519942698dc90a3951306b934bAdam Powell -1); 29368e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (streamType != AudioManager.STREAM_MUSIC) { 29378e37a85bf3dc39519942698dc90a3951306b934bAdam Powell return; 29388e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 29398e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 29408e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final int newVolume = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, 0); 29418e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final int oldVolume = intent.getIntExtra( 29428e37a85bf3dc39519942698dc90a3951306b934bAdam Powell AudioManager.EXTRA_PREV_VOLUME_STREAM_VALUE, 0); 29438e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (newVolume != oldVolume) { 29448e37a85bf3dc39519942698dc90a3951306b934bAdam Powell systemVolumeChanged(newVolume); 29458e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 29468e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 29478e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 2948705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 29498e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 2950705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell static class WifiDisplayStatusChangedReceiver extends BroadcastReceiver { 2951705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell @Override 2952705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell public void onReceive(Context context, Intent intent) { 2953705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell if (intent.getAction().equals(DisplayManager.ACTION_WIFI_DISPLAY_STATUS_CHANGED)) { 2954705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell updateWifiDisplayStatus((WifiDisplayStatus) intent.getParcelableExtra( 2955705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell DisplayManager.EXTRA_WIFI_DISPLAY_STATUS)); 2956705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 2957705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 29588e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 29599a1de308cea2d160778fd977825f10a07b49d738Adam Powell} 2960