MediaRouter.java revision 742e379863ff08a880cb6d9e5f274da7589f9a53
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 { 69eadd6d2329972129c96dee390a8b786b37313d17Hyundo Moon final String mPackageName; 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) { 113eadd6d2329972129c96dee390a8b786b37313d17Hyundo Moon mPackageName = appContext.getPackageName(); 114eadd6d2329972129c96dee390a8b786b37313d17Hyundo Moon mResources = appContext.getResources(); 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) { 179742e379863ff08a880cb6d9e5f274da7589f9a53Jaewan Kim boolean updated = false; 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); 195742e379863ff08a880cb6d9e5f274da7589f9a53Jaewan Kim updated = true; 196632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } 197bcf21e913af7252fb1994e07b6cf179321ecd049Adam Powell 1986156017c2217d0fbbbb03434986250ec6bbd69d8John Spurlock final int mainType = mCurAudioRoutesInfo.mainType; 1993f369684e13dfea0ba8ea134f3e95930b0dd7df0Adam Powell 2006156017c2217d0fbbbb03434986250ec6bbd69d8John Spurlock if (!TextUtils.equals(newRoutes.bluetoothName, mCurAudioRoutesInfo.bluetoothName)) { 2016156017c2217d0fbbbb03434986250ec6bbd69d8John Spurlock mCurAudioRoutesInfo.bluetoothName = newRoutes.bluetoothName; 2026156017c2217d0fbbbb03434986250ec6bbd69d8John Spurlock if (mCurAudioRoutesInfo.bluetoothName != null) { 203632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn if (sStatic.mBluetoothA2dpRoute == null) { 204632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn final RouteInfo info = new RouteInfo(sStatic.mSystemCategory); 2056156017c2217d0fbbbb03434986250ec6bbd69d8John Spurlock info.mName = mCurAudioRoutesInfo.bluetoothName; 20656d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown info.mDescription = sStatic.mResources.getText( 20756d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown com.android.internal.R.string.bluetooth_a2dp_audio_route_name); 208632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn info.mSupportedTypes = ROUTE_TYPE_LIVE_AUDIO; 2099dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang info.mDeviceType = RouteInfo.DEVICE_TYPE_BLUETOOTH; 210632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn sStatic.mBluetoothA2dpRoute = info; 2112ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell addRouteStatic(sStatic.mBluetoothA2dpRoute); 212632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } else { 2136156017c2217d0fbbbb03434986250ec6bbd69d8John Spurlock sStatic.mBluetoothA2dpRoute.mName = mCurAudioRoutesInfo.bluetoothName; 214632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn dispatchRouteChanged(sStatic.mBluetoothA2dpRoute); 215632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } 216632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } else if (sStatic.mBluetoothA2dpRoute != null) { 21769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown removeRouteStatic(sStatic.mBluetoothA2dpRoute); 218632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn sStatic.mBluetoothA2dpRoute = null; 219632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } 220742e379863ff08a880cb6d9e5f274da7589f9a53Jaewan Kim updated = true; 221632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } 222bcf21e913af7252fb1994e07b6cf179321ecd049Adam Powell 223bcf21e913af7252fb1994e07b6cf179321ecd049Adam Powell if (mBluetoothA2dpRoute != null) { 224fa6f70e225a7370c1ecb21ee7076c9086ecb9e9aSungsoo final boolean a2dpEnabled = isBluetoothA2dpOn(); 22571f3563c3960bd862dfa96844f646ea5b2f03de5Sungsoo if (mSelectedRoute == mBluetoothA2dpRoute && !a2dpEnabled) { 226fa6f70e225a7370c1ecb21ee7076c9086ecb9e9aSungsoo selectRouteStatic(ROUTE_TYPE_LIVE_AUDIO, mDefaultAudioVideo, false); 227742e379863ff08a880cb6d9e5f274da7589f9a53Jaewan Kim updated = true; 228fa6f70e225a7370c1ecb21ee7076c9086ecb9e9aSungsoo } else if ((mSelectedRoute == mDefaultAudioVideo || mSelectedRoute == null) && 229fa6f70e225a7370c1ecb21ee7076c9086ecb9e9aSungsoo a2dpEnabled) { 23069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown selectRouteStatic(ROUTE_TYPE_LIVE_AUDIO, mBluetoothA2dpRoute, false); 231742e379863ff08a880cb6d9e5f274da7589f9a53Jaewan Kim updated = true; 232bcf21e913af7252fb1994e07b6cf179321ecd049Adam Powell } 233bcf21e913af7252fb1994e07b6cf179321ecd049Adam Powell } 234742e379863ff08a880cb6d9e5f274da7589f9a53Jaewan Kim if (updated) { 235742e379863ff08a880cb6d9e5f274da7589f9a53Jaewan Kim Log.v(TAG, "Audio routes updated: " + newRoutes + ", a2dp=" + isBluetoothA2dpOn()); 236742e379863ff08a880cb6d9e5f274da7589f9a53Jaewan Kim } 237b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn } 23892130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown 239fa6f70e225a7370c1ecb21ee7076c9086ecb9e9aSungsoo boolean isBluetoothA2dpOn() { 240fa6f70e225a7370c1ecb21ee7076c9086ecb9e9aSungsoo try { 241fa6f70e225a7370c1ecb21ee7076c9086ecb9e9aSungsoo return mAudioService.isBluetoothA2dpOn(); 242fa6f70e225a7370c1ecb21ee7076c9086ecb9e9aSungsoo } catch (RemoteException e) { 243fa6f70e225a7370c1ecb21ee7076c9086ecb9e9aSungsoo Log.e(TAG, "Error querying Bluetooth A2DP state", e); 244fa6f70e225a7370c1ecb21ee7076c9086ecb9e9aSungsoo return false; 245fa6f70e225a7370c1ecb21ee7076c9086ecb9e9aSungsoo } 246fa6f70e225a7370c1ecb21ee7076c9086ecb9e9aSungsoo } 247fa6f70e225a7370c1ecb21ee7076c9086ecb9e9aSungsoo 24869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown void updateDiscoveryRequest() { 24969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // What are we looking for today? 25069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown int routeTypes = 0; 25169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown int passiveRouteTypes = 0; 25269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown boolean activeScan = false; 25369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown boolean activeScanWifiDisplay = false; 25469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final int count = mCallbacks.size(); 25569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown for (int i = 0; i < count; i++) { 25669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown CallbackInfo cbi = mCallbacks.get(i); 25769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if ((cbi.flags & (CALLBACK_FLAG_PERFORM_ACTIVE_SCAN 25869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown | CALLBACK_FLAG_REQUEST_DISCOVERY)) != 0) { 25969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Discovery explicitly requested. 26069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown routeTypes |= cbi.type; 26169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } else if ((cbi.flags & CALLBACK_FLAG_PASSIVE_DISCOVERY) != 0) { 26269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Discovery only passively requested. 26369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown passiveRouteTypes |= cbi.type; 26469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } else { 26569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Legacy case since applications don't specify the discovery flag. 26669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Unfortunately we just have to assume they always need discovery 26769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // whenever they have a callback registered. 26869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown routeTypes |= cbi.type; 26969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 27069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if ((cbi.flags & CALLBACK_FLAG_PERFORM_ACTIVE_SCAN) != 0) { 27169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown activeScan = true; 272af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown if ((cbi.type & ROUTE_TYPE_REMOTE_DISPLAY) != 0) { 27369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown activeScanWifiDisplay = true; 27469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 27569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 27669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 27769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (routeTypes != 0 || activeScan) { 27869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // If someone else requests discovery then enable the passive listeners. 27969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // This is used by the MediaRouteButton and MediaRouteActionProvider since 28069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // they don't receive lifecycle callbacks from the Activity. 28169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown routeTypes |= passiveRouteTypes; 28269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 28369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 28469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Update wifi display scanning. 285ce468a35b388ca46578934706b38dbae94941643Jeff Brown // TODO: All of this should be managed by the media router service. 286ce468a35b388ca46578934706b38dbae94941643Jeff Brown if (mCanConfigureWifiDisplays) { 287ce468a35b388ca46578934706b38dbae94941643Jeff Brown if (mSelectedRoute != null 288ce468a35b388ca46578934706b38dbae94941643Jeff Brown && mSelectedRoute.matchesTypes(ROUTE_TYPE_REMOTE_DISPLAY)) { 289ce468a35b388ca46578934706b38dbae94941643Jeff Brown // Don't scan while already connected to a remote display since 290ce468a35b388ca46578934706b38dbae94941643Jeff Brown // it may interfere with the ongoing transmission. 291ce468a35b388ca46578934706b38dbae94941643Jeff Brown activeScanWifiDisplay = false; 29266f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown } 293ce468a35b388ca46578934706b38dbae94941643Jeff Brown if (activeScanWifiDisplay) { 294ce468a35b388ca46578934706b38dbae94941643Jeff Brown if (!mActivelyScanningWifiDisplays) { 295ce468a35b388ca46578934706b38dbae94941643Jeff Brown mActivelyScanningWifiDisplays = true; 296ce468a35b388ca46578934706b38dbae94941643Jeff Brown mDisplayService.startWifiDisplayScan(); 297ce468a35b388ca46578934706b38dbae94941643Jeff Brown } 298ce468a35b388ca46578934706b38dbae94941643Jeff Brown } else { 299ce468a35b388ca46578934706b38dbae94941643Jeff Brown if (mActivelyScanningWifiDisplays) { 300ce468a35b388ca46578934706b38dbae94941643Jeff Brown mActivelyScanningWifiDisplays = false; 301ce468a35b388ca46578934706b38dbae94941643Jeff Brown mDisplayService.stopWifiDisplayScan(); 302ce468a35b388ca46578934706b38dbae94941643Jeff Brown } 30366f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown } 30466f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown } 30566f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown 30669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Tell the media router service all about it. 30769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (routeTypes != mDiscoveryRequestRouteTypes 30869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown || activeScan != mDiscoverRequestActiveScan) { 30969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mDiscoveryRequestRouteTypes = routeTypes; 31069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mDiscoverRequestActiveScan = activeScan; 31169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown publishClientDiscoveryRequest(); 31266f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown } 31366f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown } 31466f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown 31592130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown @Override 31692130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown public void onDisplayAdded(int displayId) { 31792130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown updatePresentationDisplays(displayId); 31892130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown } 31992130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown 32092130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown @Override 32192130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown public void onDisplayChanged(int displayId) { 32292130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown updatePresentationDisplays(displayId); 32392130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown } 32492130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown 32592130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown @Override 32692130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown public void onDisplayRemoved(int displayId) { 32792130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown updatePresentationDisplays(displayId); 32892130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown } 32992130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown 33092130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown public Display[] getAllPresentationDisplays() { 33192130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown return mDisplayService.getDisplays(DisplayManager.DISPLAY_CATEGORY_PRESENTATION); 33292130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown } 33392130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown 33492130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown private void updatePresentationDisplays(int changedDisplayId) { 33592130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown final int count = mRoutes.size(); 33692130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown for (int i = 0; i < count; i++) { 3375830b0b33618940d65197cec99d697b21908fec8Chong Zhang final RouteInfo route = mRoutes.get(i); 3385830b0b33618940d65197cec99d697b21908fec8Chong Zhang if (route.updatePresentationDisplay() || (route.mPresentationDisplay != null 3395830b0b33618940d65197cec99d697b21908fec8Chong Zhang && route.mPresentationDisplay.getDisplayId() == changedDisplayId)) { 3405830b0b33618940d65197cec99d697b21908fec8Chong Zhang dispatchRoutePresentationDisplayChanged(route); 34192130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown } 34292130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown } 34392130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown } 34469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 34569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown void setSelectedRoute(RouteInfo info, boolean explicit) { 34669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Must be non-reentrant. 34769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mSelectedRoute = info; 34869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown publishClientSelectedRoute(explicit); 34969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 35069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 35169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown void rebindAsUser(int userId) { 35269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (mCurrentUserId != userId || userId < 0 || mClient == null) { 35369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (mClient != null) { 35469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown try { 35569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mMediaRouterService.unregisterClient(mClient); 35669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } catch (RemoteException ex) { 35769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Log.e(TAG, "Unable to unregister media router client.", ex); 35869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 35969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mClient = null; 36069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 36169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 36269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mCurrentUserId = userId; 36369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 36469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown try { 36569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Client client = new Client(); 366eadd6d2329972129c96dee390a8b786b37313d17Hyundo Moon mMediaRouterService.registerClientAsUser(client, mPackageName, userId); 36769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mClient = client; 36869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } catch (RemoteException ex) { 36969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Log.e(TAG, "Unable to register media router client.", ex); 37069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 37169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 37269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown publishClientDiscoveryRequest(); 37369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown publishClientSelectedRoute(false); 37469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown updateClientState(); 37569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 37669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 37769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 37869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown void publishClientDiscoveryRequest() { 37969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (mClient != null) { 38069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown try { 38169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mMediaRouterService.setDiscoveryRequest(mClient, 38269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mDiscoveryRequestRouteTypes, mDiscoverRequestActiveScan); 38369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } catch (RemoteException ex) { 38469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Log.e(TAG, "Unable to publish media router client discovery request.", ex); 38569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 38669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 38769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 38869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 38969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown void publishClientSelectedRoute(boolean explicit) { 39069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (mClient != null) { 39169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown try { 39269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mMediaRouterService.setSelectedRoute(mClient, 39369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mSelectedRoute != null ? mSelectedRoute.mGlobalRouteId : null, 39469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown explicit); 39569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } catch (RemoteException ex) { 39669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Log.e(TAG, "Unable to publish media router client selected route.", ex); 39769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 39869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 39969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 40069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 40169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown void updateClientState() { 40269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Update the client state. 40369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mClientState = null; 40469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (mClient != null) { 40569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown try { 40669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mClientState = mMediaRouterService.getState(mClient); 40769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } catch (RemoteException ex) { 40869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Log.e(TAG, "Unable to retrieve media router client state.", ex); 40969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 41069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 41169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final ArrayList<MediaRouterClientState.RouteInfo> globalRoutes = 41269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mClientState != null ? mClientState.routes : null; 41369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final String globallySelectedRouteId = mClientState != null ? 41469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mClientState.globallySelectedRouteId : null; 41569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 41669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Add or update routes. 41769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final int globalRouteCount = globalRoutes != null ? globalRoutes.size() : 0; 41869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown for (int i = 0; i < globalRouteCount; i++) { 41969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final MediaRouterClientState.RouteInfo globalRoute = globalRoutes.get(i); 42069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown RouteInfo route = findGlobalRoute(globalRoute.id); 42169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (route == null) { 42269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route = makeGlobalRoute(globalRoute); 42369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown addRouteStatic(route); 42469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } else { 42569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown updateGlobalRoute(route, globalRoute); 42669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 42769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 42869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 42969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Synchronize state with the globally selected route. 43069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (globallySelectedRouteId != null) { 43169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final RouteInfo route = findGlobalRoute(globallySelectedRouteId); 43269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (route == null) { 43369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Log.w(TAG, "Could not find new globally selected route: " 43469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown + globallySelectedRouteId); 43569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } else if (route != mSelectedRoute) { 43669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (DEBUG) { 43769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Log.d(TAG, "Selecting new globally selected route: " + route); 43869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 43969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown selectRouteStatic(route.mSupportedTypes, route, false); 44069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 44169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } else if (mSelectedRoute != null && mSelectedRoute.mGlobalRouteId != null) { 44269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (DEBUG) { 44369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Log.d(TAG, "Unselecting previous globally selected route: " + mSelectedRoute); 44469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 44569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown selectDefaultRouteStatic(); 44669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 44769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 44869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Remove defunct routes. 44969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown outer: for (int i = mRoutes.size(); i-- > 0; ) { 45069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final RouteInfo route = mRoutes.get(i); 45169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final String globalRouteId = route.mGlobalRouteId; 45269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (globalRouteId != null) { 45369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown for (int j = 0; j < globalRouteCount; j++) { 45469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown MediaRouterClientState.RouteInfo globalRoute = globalRoutes.get(j); 45569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (globalRouteId.equals(globalRoute.id)) { 45669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown continue outer; // found 45769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 45869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 45969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // not found 46069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown removeRouteStatic(route); 46169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 46269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 46369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 46469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 46569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown void requestSetVolume(RouteInfo route, int volume) { 46669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (route.mGlobalRouteId != null && mClient != null) { 46769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown try { 46869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mMediaRouterService.requestSetVolume(mClient, 46969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mGlobalRouteId, volume); 47069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } catch (RemoteException ex) { 47169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Log.w(TAG, "Unable to request volume change.", ex); 47269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 47369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 47469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 47569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 47669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown void requestUpdateVolume(RouteInfo route, int direction) { 47769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (route.mGlobalRouteId != null && mClient != null) { 47869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown try { 47969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mMediaRouterService.requestUpdateVolume(mClient, 48069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mGlobalRouteId, direction); 48169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } catch (RemoteException ex) { 48269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Log.w(TAG, "Unable to request volume change.", ex); 48369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 48469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 48569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 48669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 48769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown RouteInfo makeGlobalRoute(MediaRouterClientState.RouteInfo globalRoute) { 48869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown RouteInfo route = new RouteInfo(sStatic.mSystemCategory); 48969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mGlobalRouteId = globalRoute.id; 49069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mName = globalRoute.name; 49169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mDescription = globalRoute.description; 49269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mSupportedTypes = globalRoute.supportedTypes; 4939dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang route.mDeviceType = globalRoute.deviceType; 49469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mEnabled = globalRoute.enabled; 49539ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown route.setRealStatusCode(globalRoute.statusCode); 49669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mPlaybackType = globalRoute.playbackType; 49769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mPlaybackStream = globalRoute.playbackStream; 49869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mVolume = globalRoute.volume; 49969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mVolumeMax = globalRoute.volumeMax; 50069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mVolumeHandling = globalRoute.volumeHandling; 5015830b0b33618940d65197cec99d697b21908fec8Chong Zhang route.mPresentationDisplayId = globalRoute.presentationDisplayId; 5025830b0b33618940d65197cec99d697b21908fec8Chong Zhang route.updatePresentationDisplay(); 50369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return route; 50469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 50569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 50669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown void updateGlobalRoute(RouteInfo route, MediaRouterClientState.RouteInfo globalRoute) { 50769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown boolean changed = false; 50869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown boolean volumeChanged = false; 50969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown boolean presentationDisplayChanged = false; 51069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 511e6585b32ea586743258a5457e2184ffc087f2d2fKenny Root if (!Objects.equals(route.mName, globalRoute.name)) { 51269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mName = globalRoute.name; 51369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown changed = true; 51469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 515e6585b32ea586743258a5457e2184ffc087f2d2fKenny Root if (!Objects.equals(route.mDescription, globalRoute.description)) { 51669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mDescription = globalRoute.description; 51769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown changed = true; 51869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 519af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown final int oldSupportedTypes = route.mSupportedTypes; 520af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown if (oldSupportedTypes != globalRoute.supportedTypes) { 52169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mSupportedTypes = globalRoute.supportedTypes; 52269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown changed = true; 52369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 52469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (route.mEnabled != globalRoute.enabled) { 52569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mEnabled = globalRoute.enabled; 52669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown changed = true; 52769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 52839ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown if (route.mRealStatusCode != globalRoute.statusCode) { 52939ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown route.setRealStatusCode(globalRoute.statusCode); 53069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown changed = true; 53169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 53269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (route.mPlaybackType != globalRoute.playbackType) { 53369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mPlaybackType = globalRoute.playbackType; 53469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown changed = true; 53569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 53669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (route.mPlaybackStream != globalRoute.playbackStream) { 53769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mPlaybackStream = globalRoute.playbackStream; 53869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown changed = true; 53969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 54069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (route.mVolume != globalRoute.volume) { 54169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mVolume = globalRoute.volume; 54269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown changed = true; 54369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown volumeChanged = true; 54469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 54569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (route.mVolumeMax != globalRoute.volumeMax) { 54669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mVolumeMax = globalRoute.volumeMax; 54769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown changed = true; 54869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown volumeChanged = true; 54969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 55069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (route.mVolumeHandling != globalRoute.volumeHandling) { 55169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mVolumeHandling = globalRoute.volumeHandling; 55269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown changed = true; 55369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown volumeChanged = true; 55469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 5555830b0b33618940d65197cec99d697b21908fec8Chong Zhang if (route.mPresentationDisplayId != globalRoute.presentationDisplayId) { 5565830b0b33618940d65197cec99d697b21908fec8Chong Zhang route.mPresentationDisplayId = globalRoute.presentationDisplayId; 5575830b0b33618940d65197cec99d697b21908fec8Chong Zhang route.updatePresentationDisplay(); 55869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown changed = true; 55969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown presentationDisplayChanged = true; 56069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 56169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 56269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (changed) { 563af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown dispatchRouteChanged(route, oldSupportedTypes); 56469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 56569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (volumeChanged) { 56669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown dispatchRouteVolumeChanged(route); 56769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 56869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (presentationDisplayChanged) { 56969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown dispatchRoutePresentationDisplayChanged(route); 57069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 57169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 57269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 57369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown RouteInfo findGlobalRoute(String globalRouteId) { 57469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final int count = mRoutes.size(); 57569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown for (int i = 0; i < count; i++) { 57669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final RouteInfo route = mRoutes.get(i); 57769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (globalRouteId.equals(route.mGlobalRouteId)) { 57869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return route; 57969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 58069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 58169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return null; 58269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 58369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 58469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final class Client extends IMediaRouterClient.Stub { 58569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown @Override 58669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public void onStateChanged() { 58769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mHandler.post(new Runnable() { 58869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown @Override 58969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public void run() { 59069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (Client.this == mClient) { 59169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown updateClientState(); 59269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 59369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 59469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown }); 59569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 59669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 597b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn } 5989a1de308cea2d160778fd977825f10a07b49d738Adam Powell 599b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn static Static sStatic; 6009a1de308cea2d160778fd977825f10a07b49d738Adam Powell 6019a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 6029a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Route type flag for live audio. 6039a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 6049a1de308cea2d160778fd977825f10a07b49d738Adam Powell * <p>A device that supports live audio routing will allow the media audio stream 6059a1de308cea2d160778fd977825f10a07b49d738Adam Powell * to be routed to supported destinations. This can include internal speakers or 6069a1de308cea2d160778fd977825f10a07b49d738Adam Powell * audio jacks on the device itself, A2DP devices, and more.</p> 6079a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 6089a1de308cea2d160778fd977825f10a07b49d738Adam Powell * <p>Once initiated this routing is transparent to the application. All audio 6099a1de308cea2d160778fd977825f10a07b49d738Adam Powell * played on the media stream will be routed to the selected destination.</p> 6109a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 61169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public static final int ROUTE_TYPE_LIVE_AUDIO = 1 << 0; 6129a1de308cea2d160778fd977825f10a07b49d738Adam Powell 6139a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 614705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell * Route type flag for live video. 615705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell * 616705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell * <p>A device that supports live video routing will allow a mirrored version 617705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell * of the device's primary display or a customized 618705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell * {@link android.app.Presentation Presentation} to be routed to supported destinations.</p> 619705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell * 620705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell * <p>Once initiated, display mirroring is transparent to the application. 621705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell * While remote routing is active the application may use a 622705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell * {@link android.app.Presentation Presentation} to replace the mirrored view 623705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell * on the external display with different content.</p> 62492130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * 62592130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * @see RouteInfo#getPresentationDisplay() 62692130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * @see android.app.Presentation 627705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell */ 62869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public static final int ROUTE_TYPE_LIVE_VIDEO = 1 << 1; 62969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 63069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown /** 63169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * Temporary interop constant to identify remote displays. 63269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * @hide To be removed when media router API is updated. 63369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown */ 63469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public static final int ROUTE_TYPE_REMOTE_DISPLAY = 1 << 2; 635705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 636705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell /** 6379a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Route type flag for application-specific usage. 6389a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 6399a1de308cea2d160778fd977825f10a07b49d738Adam Powell * <p>Unlike other media route types, user routes are managed by the application. 6409a1de308cea2d160778fd977825f10a07b49d738Adam Powell * The MediaRouter will manage and dispatch events for user routes, but the application 6419a1de308cea2d160778fd977825f10a07b49d738Adam Powell * is expected to interpret the meaning of these events and perform the requested 6429a1de308cea2d160778fd977825f10a07b49d738Adam Powell * routing tasks.</p> 6439a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 64469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public static final int ROUTE_TYPE_USER = 1 << 23; 64569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 64669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown static final int ROUTE_TYPE_ANY = ROUTE_TYPE_LIVE_AUDIO | ROUTE_TYPE_LIVE_VIDEO 64769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown | ROUTE_TYPE_REMOTE_DISPLAY | ROUTE_TYPE_USER; 6489a1de308cea2d160778fd977825f10a07b49d738Adam Powell 64966f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown /** 65066f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * Flag for {@link #addCallback}: Actively scan for routes while this callback 65166f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * is registered. 65266f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * <p> 65366f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * When this flag is specified, the media router will actively scan for new 65466f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * routes. Certain routes, such as wifi display routes, may not be discoverable 65566f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * except when actively scanning. This flag is typically used when the route picker 65666f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * dialog has been opened by the user to ensure that the route information is 65766f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * up to date. 65866f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * </p><p> 65966f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * Active scanning may consume a significant amount of power and may have intrusive 66066f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * effects on wireless connectivity. Therefore it is important that active scanning 66166f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * only be requested when it is actually needed to satisfy a user request to 66266f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * discover and select a new route. 66366f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * </p> 66466f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown */ 66514507e257af5d71577574e25cbd690c4b54c9272Jeff Brown public static final int CALLBACK_FLAG_PERFORM_ACTIVE_SCAN = 1 << 0; 66666f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown 66766f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown /** 66866f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * Flag for {@link #addCallback}: Do not filter route events. 66966f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * <p> 67066f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * When this flag is specified, the callback will be invoked for event that affect any 67169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * route even if they do not match the callback's filter. 67266f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * </p> 67366f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown */ 67466f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown public static final int CALLBACK_FLAG_UNFILTERED_EVENTS = 1 << 1; 67566f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown 67669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown /** 67769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * Explicitly requests discovery. 67869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * 67969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * @hide Future API ported from support library. Revisit this later. 68069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown */ 68169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public static final int CALLBACK_FLAG_REQUEST_DISCOVERY = 1 << 2; 68269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 68369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown /** 68469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * Requests that discovery be performed but only if there is some other active 68569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * callback already registered. 68669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * 68769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * @hide Compatibility workaround for the fact that applications do not currently 68869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * request discovery explicitly (except when using the support library API). 68969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown */ 69069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public static final int CALLBACK_FLAG_PASSIVE_DISCOVERY = 1 << 3; 69169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 6920abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown /** 6930abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * Flag for {@link #isRouteAvailable}: Ignore the default route. 6940abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * <p> 6950abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * This flag is used to determine whether a matching non-default route is available. 6960abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * This constraint may be used to decide whether to offer the route chooser dialog 6970abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * to the user. There is no point offering the chooser if there are no 6980abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * non-default choices. 6990abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * </p> 7000abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * 7010abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * @hide Future API ported from support library. Revisit this later. 7020abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown */ 7030abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown public static final int AVAILABILITY_FLAG_IGNORE_DEFAULT_ROUTE = 1 << 0; 7040abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown 7059a1de308cea2d160778fd977825f10a07b49d738Adam Powell // Maps application contexts 7069a1de308cea2d160778fd977825f10a07b49d738Adam Powell static final HashMap<Context, MediaRouter> sRouters = new HashMap<Context, MediaRouter>(); 7079a1de308cea2d160778fd977825f10a07b49d738Adam Powell 7089a1de308cea2d160778fd977825f10a07b49d738Adam Powell static String typesToString(int types) { 7099a1de308cea2d160778fd977825f10a07b49d738Adam Powell final StringBuilder result = new StringBuilder(); 7109a1de308cea2d160778fd977825f10a07b49d738Adam Powell if ((types & ROUTE_TYPE_LIVE_AUDIO) != 0) { 7119a1de308cea2d160778fd977825f10a07b49d738Adam Powell result.append("ROUTE_TYPE_LIVE_AUDIO "); 7129a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 7132bb7c122ef6ce8539dfbaeb3292adcd942185f82Bryan Mawhinney if ((types & ROUTE_TYPE_LIVE_VIDEO) != 0) { 7142bb7c122ef6ce8539dfbaeb3292adcd942185f82Bryan Mawhinney result.append("ROUTE_TYPE_LIVE_VIDEO "); 7152bb7c122ef6ce8539dfbaeb3292adcd942185f82Bryan Mawhinney } 71669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if ((types & ROUTE_TYPE_REMOTE_DISPLAY) != 0) { 71769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown result.append("ROUTE_TYPE_REMOTE_DISPLAY "); 71869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 7199a1de308cea2d160778fd977825f10a07b49d738Adam Powell if ((types & ROUTE_TYPE_USER) != 0) { 7209a1de308cea2d160778fd977825f10a07b49d738Adam Powell result.append("ROUTE_TYPE_USER "); 7219a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 7229a1de308cea2d160778fd977825f10a07b49d738Adam Powell return result.toString(); 7239a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 7249a1de308cea2d160778fd977825f10a07b49d738Adam Powell 725b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn /** @hide */ 726b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn public MediaRouter(Context context) { 727b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn synchronized (Static.class) { 728b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn if (sStatic == null) { 7298e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final Context appContext = context.getApplicationContext(); 7308e37a85bf3dc39519942698dc90a3951306b934bAdam Powell sStatic = new Static(appContext); 7318e37a85bf3dc39519942698dc90a3951306b934bAdam Powell sStatic.startMonitoringRoutes(appContext); 732b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn } 7339a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 7349a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 7359a1de308cea2d160778fd977825f10a07b49d738Adam Powell 736690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell /** 7373afc18af2cea898753b10e8575dcf20c11356bcaJeff Brown * Gets the default route for playing media content on the system. 7383afc18af2cea898753b10e8575dcf20c11356bcaJeff Brown * <p> 7393afc18af2cea898753b10e8575dcf20c11356bcaJeff Brown * The system always provides a default route. 7403afc18af2cea898753b10e8575dcf20c11356bcaJeff Brown * </p> 7413afc18af2cea898753b10e8575dcf20c11356bcaJeff Brown * 7423afc18af2cea898753b10e8575dcf20c11356bcaJeff Brown * @return The default route, which is guaranteed to never be null. 743690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell */ 7443afc18af2cea898753b10e8575dcf20c11356bcaJeff Brown public RouteInfo getDefaultRoute() { 745705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell return sStatic.mDefaultAudioVideo; 746690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell } 747690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell 748690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell /** 7494599696591f745b3a546197d2ba7e5cfc5562484Adam Powell * @hide for use by framework routing UI 7504599696591f745b3a546197d2ba7e5cfc5562484Adam Powell */ 7513afc18af2cea898753b10e8575dcf20c11356bcaJeff Brown public RouteCategory getSystemCategory() { 7524599696591f745b3a546197d2ba7e5cfc5562484Adam Powell return sStatic.mSystemCategory; 7534599696591f745b3a546197d2ba7e5cfc5562484Adam Powell } 7544599696591f745b3a546197d2ba7e5cfc5562484Adam Powell 7550abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown /** @hide */ 7560abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown public RouteInfo getSelectedRoute() { 7570abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown return getSelectedRoute(ROUTE_TYPE_ANY); 7580abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown } 7590abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown 7604599696591f745b3a546197d2ba7e5cfc5562484Adam Powell /** 7611cf2ca83584a4cf0aa3ded787bd191b9a60e3521Adam Powell * Return the currently selected route for any of the given types 762690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell * 763690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell * @param type route types 764690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell * @return the selected route 765690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell */ 766690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell public RouteInfo getSelectedRoute(int type) { 7671cf2ca83584a4cf0aa3ded787bd191b9a60e3521Adam Powell if (sStatic.mSelectedRoute != null && 7681cf2ca83584a4cf0aa3ded787bd191b9a60e3521Adam Powell (sStatic.mSelectedRoute.mSupportedTypes & type) != 0) { 7691cf2ca83584a4cf0aa3ded787bd191b9a60e3521Adam Powell // If the selected route supports any of the types supplied, it's still considered 7701cf2ca83584a4cf0aa3ded787bd191b9a60e3521Adam Powell // 'selected' for that type. 7711cf2ca83584a4cf0aa3ded787bd191b9a60e3521Adam Powell return sStatic.mSelectedRoute; 7721cf2ca83584a4cf0aa3ded787bd191b9a60e3521Adam Powell } else if (type == ROUTE_TYPE_USER) { 7731cf2ca83584a4cf0aa3ded787bd191b9a60e3521Adam Powell // The caller specifically asked for a user route and the currently selected route 7741cf2ca83584a4cf0aa3ded787bd191b9a60e3521Adam Powell // doesn't qualify. 7751cf2ca83584a4cf0aa3ded787bd191b9a60e3521Adam Powell return null; 7761cf2ca83584a4cf0aa3ded787bd191b9a60e3521Adam Powell } 7771cf2ca83584a4cf0aa3ded787bd191b9a60e3521Adam Powell // If the above didn't match and we're not specifically asking for a user route, 7781cf2ca83584a4cf0aa3ded787bd191b9a60e3521Adam Powell // consider the default selected. 7791cf2ca83584a4cf0aa3ded787bd191b9a60e3521Adam Powell return sStatic.mDefaultAudioVideo; 780690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell } 781690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell 7829a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 7830abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * Returns true if there is a route that matches the specified types. 7840abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * <p> 7850abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * This method returns true if there are any available routes that match the types 7860abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * regardless of whether they are enabled or disabled. If the 7870abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * {@link #AVAILABILITY_FLAG_IGNORE_DEFAULT_ROUTE} flag is specified, then 7880abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * the method will only consider non-default routes. 7890abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * </p> 7900abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * 7910abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * @param types The types to match. 7920abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * @param flags Flags to control the determination of whether a route may be available. 7930abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * May be zero or {@link #AVAILABILITY_FLAG_IGNORE_DEFAULT_ROUTE}. 7940abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * @return True if a matching route may be available. 7950abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * 7960abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * @hide Future API ported from support library. Revisit this later. 7970abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown */ 7980abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown public boolean isRouteAvailable(int types, int flags) { 7990abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown final int count = sStatic.mRoutes.size(); 8000abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown for (int i = 0; i < count; i++) { 8010abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown RouteInfo route = sStatic.mRoutes.get(i); 8020abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown if (route.matchesTypes(types)) { 8030abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown if ((flags & AVAILABILITY_FLAG_IGNORE_DEFAULT_ROUTE) == 0 8040abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown || route != sStatic.mDefaultAudioVideo) { 8050abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown return true; 8060abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown } 8070abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown } 8080abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown } 8090abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown 8100abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown // It doesn't look like we can find a matching route right now. 8110abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown return false; 8120abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown } 8130abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown 8140abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown /** 8159a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Add a callback to listen to events about specific kinds of media routes. 8169a1de308cea2d160778fd977825f10a07b49d738Adam Powell * If the specified callback is already registered, its registration will be updated for any 8179a1de308cea2d160778fd977825f10a07b49d738Adam Powell * additional route types specified. 81866f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * <p> 81966f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * This is a convenience method that has the same effect as calling 82066f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * {@link #addCallback(int, Callback, int)} without flags. 82166f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * </p> 8229a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 8239a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param types Types of routes this callback is interested in 8249a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param cb Callback to add 8259a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 8269a1de308cea2d160778fd977825f10a07b49d738Adam Powell public void addCallback(int types, Callback cb) { 82766f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown addCallback(types, cb, 0); 82866f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown } 82966f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown 83066f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown /** 83166f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * Add a callback to listen to events about specific kinds of media routes. 83266f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * If the specified callback is already registered, its registration will be updated for any 83366f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * additional route types specified. 83466f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * <p> 83566f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * By default, the callback will only be invoked for events that affect routes 83666f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * that match the specified selector. The filtering may be disabled by specifying 83766f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * the {@link #CALLBACK_FLAG_UNFILTERED_EVENTS} flag. 83866f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * </p> 83966f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * 84066f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * @param types Types of routes this callback is interested in 84166f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * @param cb Callback to add 84266f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * @param flags Flags to control the behavior of the callback. 84314507e257af5d71577574e25cbd690c4b54c9272Jeff Brown * May be zero or a combination of {@link #CALLBACK_FLAG_PERFORM_ACTIVE_SCAN} and 84466f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * {@link #CALLBACK_FLAG_UNFILTERED_EVENTS}. 84566f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown */ 84666f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown public void addCallback(int types, Callback cb, int flags) { 84766f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown CallbackInfo info; 84866f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown int index = findCallbackInfo(cb); 84966f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown if (index >= 0) { 85066f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown info = sStatic.mCallbacks.get(index); 85166f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown info.type |= types; 85266f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown info.flags |= flags; 85366f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown } else { 85466f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown info = new CallbackInfo(cb, types, flags, this); 85566f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown sStatic.mCallbacks.add(info); 85666f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown } 85769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown sStatic.updateDiscoveryRequest(); 8589a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 8599a1de308cea2d160778fd977825f10a07b49d738Adam Powell 8609a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 8619a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Remove the specified callback. It will no longer receive events about media routing. 8629a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 8639a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param cb Callback to remove 8649a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 8659a1de308cea2d160778fd977825f10a07b49d738Adam Powell public void removeCallback(Callback cb) { 86666f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown int index = findCallbackInfo(cb); 86766f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown if (index >= 0) { 86869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown sStatic.mCallbacks.remove(index); 86969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown sStatic.updateDiscoveryRequest(); 87066f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown } else { 87166f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown Log.w(TAG, "removeCallback(" + cb + "): callback not registered"); 87266f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown } 87366f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown } 87466f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown 87566f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown private int findCallbackInfo(Callback cb) { 876b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn final int count = sStatic.mCallbacks.size(); 8779a1de308cea2d160778fd977825f10a07b49d738Adam Powell for (int i = 0; i < count; i++) { 87866f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown final CallbackInfo info = sStatic.mCallbacks.get(i); 87966f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown if (info.cb == cb) { 88066f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown return i; 8819a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 8829a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 88366f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown return -1; 8849a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 8859a1de308cea2d160778fd977825f10a07b49d738Adam Powell 886d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell /** 887d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * Select the specified route to use for output of the given media types. 8883afc18af2cea898753b10e8575dcf20c11356bcaJeff Brown * <p class="note"> 8893afc18af2cea898753b10e8575dcf20c11356bcaJeff Brown * As API version 18, this function may be used to select any route. 8903afc18af2cea898753b10e8575dcf20c11356bcaJeff Brown * In prior versions, this function could only be used to select user 8913afc18af2cea898753b10e8575dcf20c11356bcaJeff Brown * routes and would ignore any attempt to select a system route. 8923afc18af2cea898753b10e8575dcf20c11356bcaJeff Brown * </p> 893d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * 894d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param types type flags indicating which types this route should be used for. 895d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * The route must support at least a subset. 896d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param route Route to select 8979d93a378c5158d14f80d46af70433234330ec568P.Y. Laligand * @throws IllegalArgumentException if the given route is {@code null} 898d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell */ 8999d93a378c5158d14f80d46af70433234330ec568P.Y. Laligand public void selectRoute(int types, @NonNull RouteInfo route) { 9009d93a378c5158d14f80d46af70433234330ec568P.Y. Laligand if (route == null) { 9019d93a378c5158d14f80d46af70433234330ec568P.Y. Laligand throw new IllegalArgumentException("Route cannot be null."); 9029d93a378c5158d14f80d46af70433234330ec568P.Y. Laligand } 90369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown selectRouteStatic(types, route, true); 9040d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell } 90569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 9060d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell /** 9070d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * @hide internal use 9080d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell */ 90969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public void selectRouteInt(int types, RouteInfo route, boolean explicit) { 91069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown selectRouteStatic(types, route, explicit); 911b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn } 912b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn 9139d93a378c5158d14f80d46af70433234330ec568P.Y. Laligand static void selectRouteStatic(int types, @NonNull RouteInfo route, boolean explicit) { 91418687b7a275b3782e63d52cdbe8ee9df191046e7Jae Seo Log.v(TAG, "Selecting route: " + route); 9159d93a378c5158d14f80d46af70433234330ec568P.Y. Laligand assert(route != null); 916705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell final RouteInfo oldRoute = sStatic.mSelectedRoute; 917705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell if (oldRoute == route) return; 9180abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown if (!route.matchesTypes(types)) { 9190d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell Log.w(TAG, "selectRoute ignored; cannot select route with supported types " + 9200d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell typesToString(route.getSupportedTypes()) + " into route types " + 9210d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell typesToString(types)); 9224ee1f55ce0f4909a7430ab44563a81852f335071Adam Powell return; 9230d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell } 9249a1de308cea2d160778fd977825f10a07b49d738Adam Powell 925fa6f70e225a7370c1ecb21ee7076c9086ecb9e9aSungsoo final RouteInfo btRoute = sStatic.mBluetoothA2dpRoute; 926fa6f70e225a7370c1ecb21ee7076c9086ecb9e9aSungsoo if (btRoute != null && (types & ROUTE_TYPE_LIVE_AUDIO) != 0 && 927fa6f70e225a7370c1ecb21ee7076c9086ecb9e9aSungsoo (route == btRoute || route == sStatic.mDefaultAudioVideo)) { 928fa6f70e225a7370c1ecb21ee7076c9086ecb9e9aSungsoo try { 929fa6f70e225a7370c1ecb21ee7076c9086ecb9e9aSungsoo sStatic.mAudioService.setBluetoothA2dpOn(route == btRoute); 930fa6f70e225a7370c1ecb21ee7076c9086ecb9e9aSungsoo } catch (RemoteException e) { 931fa6f70e225a7370c1ecb21ee7076c9086ecb9e9aSungsoo Log.e(TAG, "Error changing Bluetooth A2DP state", e); 932fa6f70e225a7370c1ecb21ee7076c9086ecb9e9aSungsoo } 933fa6f70e225a7370c1ecb21ee7076c9086ecb9e9aSungsoo } 934fa6f70e225a7370c1ecb21ee7076c9086ecb9e9aSungsoo 935705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell final WifiDisplay activeDisplay = 936705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell sStatic.mDisplayService.getWifiDisplayStatus().getActiveDisplay(); 937705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell final boolean oldRouteHasAddress = oldRoute != null && oldRoute.mDeviceAddress != null; 9389d93a378c5158d14f80d46af70433234330ec568P.Y. Laligand final boolean newRouteHasAddress = route.mDeviceAddress != null; 939705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell if (activeDisplay != null || oldRouteHasAddress || newRouteHasAddress) { 940705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell if (newRouteHasAddress && !matchesDeviceAddress(activeDisplay, route)) { 941af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown if (sStatic.mCanConfigureWifiDisplays) { 942af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown sStatic.mDisplayService.connectWifiDisplay(route.mDeviceAddress); 943af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown } else { 944af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown Log.e(TAG, "Cannot connect to wifi displays because this process " 945af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown + "is not allowed to do so."); 946af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown } 947705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } else if (activeDisplay != null && !newRouteHasAddress) { 948705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell sStatic.mDisplayService.disconnectWifiDisplay(); 949705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 950705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 951705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 95269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown sStatic.setSelectedRoute(route, explicit); 95369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 954705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell if (oldRoute != null) { 955705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell dispatchRouteUnselected(types & oldRoute.getSupportedTypes(), oldRoute); 95639ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown if (oldRoute.resolveStatusCode()) { 95739ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown dispatchRouteChanged(oldRoute); 95839ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown } 9599a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 9609a1de308cea2d160778fd977825f10a07b49d738Adam Powell if (route != null) { 96139ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown if (route.resolveStatusCode()) { 96239ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown dispatchRouteChanged(route); 96339ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown } 9649a1de308cea2d160778fd977825f10a07b49d738Adam Powell dispatchRouteSelected(types & route.getSupportedTypes(), route); 9659a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 966ce468a35b388ca46578934706b38dbae94941643Jeff Brown 967ce468a35b388ca46578934706b38dbae94941643Jeff Brown // The behavior of active scans may depend on the currently selected route. 968ce468a35b388ca46578934706b38dbae94941643Jeff Brown sStatic.updateDiscoveryRequest(); 9699a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 9709a1de308cea2d160778fd977825f10a07b49d738Adam Powell 97169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown static void selectDefaultRouteStatic() { 97269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // TODO: Be smarter about the route types here; this selects for all valid. 97369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (sStatic.mSelectedRoute != sStatic.mBluetoothA2dpRoute 974fa6f70e225a7370c1ecb21ee7076c9086ecb9e9aSungsoo && sStatic.mBluetoothA2dpRoute != null && sStatic.isBluetoothA2dpOn()) { 97569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown selectRouteStatic(ROUTE_TYPE_ANY, sStatic.mBluetoothA2dpRoute, false); 97669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } else { 97769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown selectRouteStatic(ROUTE_TYPE_ANY, sStatic.mDefaultAudioVideo, false); 97869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 97969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 98069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 9819a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 982705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell * Compare the device address of a display and a route. 983705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell * Nulls/no device address will match another null/no address. 984705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell */ 985705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell static boolean matchesDeviceAddress(WifiDisplay display, RouteInfo info) { 986705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell final boolean routeHasAddress = info != null && info.mDeviceAddress != null; 987705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell if (display == null && !routeHasAddress) { 988705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell return true; 989705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 990705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 991705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell if (display != null && routeHasAddress) { 992705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell return display.getDeviceAddress().equals(info.mDeviceAddress); 993705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 994705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell return false; 995705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 996705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 997705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell /** 9989a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Add an app-specified route for media to the MediaRouter. 9999a1de308cea2d160778fd977825f10a07b49d738Adam Powell * App-specified route definitions are created using {@link #createUserRoute(RouteCategory)} 10009a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 10019a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param info Definition of the route to add 10023afc18af2cea898753b10e8575dcf20c11356bcaJeff Brown * @see #createUserRoute(RouteCategory) 10039a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @see #removeUserRoute(UserRouteInfo) 10049a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 10059a1de308cea2d160778fd977825f10a07b49d738Adam Powell public void addUserRoute(UserRouteInfo info) { 10062ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell addRouteStatic(info); 10079a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 10089a1de308cea2d160778fd977825f10a07b49d738Adam Powell 1009d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell /** 1010d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell * @hide Framework use only 1011d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell */ 1012d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell public void addRouteInt(RouteInfo info) { 10132ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell addRouteStatic(info); 1014d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell } 1015d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell 10162ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell static void addRouteStatic(RouteInfo info) { 101718687b7a275b3782e63d52cdbe8ee9df191046e7Jae Seo Log.v(TAG, "Adding route: " + info); 10189a1de308cea2d160778fd977825f10a07b49d738Adam Powell final RouteCategory cat = info.getCategory(); 1019b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn if (!sStatic.mCategories.contains(cat)) { 1020b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn sStatic.mCategories.add(cat); 10219a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 1022d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell if (cat.isGroupable() && !(info instanceof RouteGroup)) { 10239a1de308cea2d160778fd977825f10a07b49d738Adam Powell // Enforce that any added route in a groupable category must be in a group. 10249a1de308cea2d160778fd977825f10a07b49d738Adam Powell final RouteGroup group = new RouteGroup(info.getCategory()); 1025dbbfa702a09f6d2d36dee1b552442d04a4673f89Adam Powell group.mSupportedTypes = info.mSupportedTypes; 1026b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn sStatic.mRoutes.add(group); 1027d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell dispatchRouteAdded(group); 1028b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell group.addRoute(info); 1029d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell 10309a1de308cea2d160778fd977825f10a07b49d738Adam Powell info = group; 1031d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell } else { 1032b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn sStatic.mRoutes.add(info); 1033d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell dispatchRouteAdded(info); 10349a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 10359a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 10369a1de308cea2d160778fd977825f10a07b49d738Adam Powell 10379a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 10389a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Remove an app-specified route for media from the MediaRouter. 10399a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 10409a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param info Definition of the route to remove 10419a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @see #addUserRoute(UserRouteInfo) 10429a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 10439a1de308cea2d160778fd977825f10a07b49d738Adam Powell public void removeUserRoute(UserRouteInfo info) { 104469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown removeRouteStatic(info); 10459a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 10469a1de308cea2d160778fd977825f10a07b49d738Adam Powell 1047690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell /** 1048690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell * Remove all app-specified routes from the MediaRouter. 1049690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell * 1050690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell * @see #removeUserRoute(UserRouteInfo) 1051690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell */ 1052690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell public void clearUserRoutes() { 1053b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn for (int i = 0; i < sStatic.mRoutes.size(); i++) { 1054b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn final RouteInfo info = sStatic.mRoutes.get(i); 1055d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell // TODO Right now, RouteGroups only ever contain user routes. 1056d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell // The code below will need to change if this assumption does. 1057d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell if (info instanceof UserRouteInfo || info instanceof RouteGroup) { 105869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown removeRouteStatic(info); 1059690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell i--; 1060690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell } 1061690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell } 1062690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell } 1063690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell 1064d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell /** 1065d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell * @hide internal use only 1066d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell */ 1067d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell public void removeRouteInt(RouteInfo info) { 106869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown removeRouteStatic(info); 1069d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell } 1070d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell 107169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown static void removeRouteStatic(RouteInfo info) { 107218687b7a275b3782e63d52cdbe8ee9df191046e7Jae Seo Log.v(TAG, "Removing route: " + info); 1073b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn if (sStatic.mRoutes.remove(info)) { 10749a1de308cea2d160778fd977825f10a07b49d738Adam Powell final RouteCategory removingCat = info.getCategory(); 1075b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn final int count = sStatic.mRoutes.size(); 10769a1de308cea2d160778fd977825f10a07b49d738Adam Powell boolean found = false; 10779a1de308cea2d160778fd977825f10a07b49d738Adam Powell for (int i = 0; i < count; i++) { 1078b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn final RouteCategory cat = sStatic.mRoutes.get(i).getCategory(); 10799a1de308cea2d160778fd977825f10a07b49d738Adam Powell if (removingCat == cat) { 10809a1de308cea2d160778fd977825f10a07b49d738Adam Powell found = true; 10819a1de308cea2d160778fd977825f10a07b49d738Adam Powell break; 10829a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 10839a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 10840abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown if (info.isSelected()) { 1085d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell // Removing the currently selected route? Select the default before we remove it. 108669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown selectDefaultRouteStatic(); 1087d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell } 1088690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell if (!found) { 1089b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn sStatic.mCategories.remove(removingCat); 1090690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell } 1091690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell dispatchRouteRemoved(info); 1092690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell } 1093690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell } 1094690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell 10959a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 10969a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Return the number of {@link MediaRouter.RouteCategory categories} currently 10979a1de308cea2d160778fd977825f10a07b49d738Adam Powell * represented by routes known to this MediaRouter. 10989a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 10999a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @return the number of unique categories represented by this MediaRouter's known routes 11009a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 11019a1de308cea2d160778fd977825f10a07b49d738Adam Powell public int getCategoryCount() { 1102b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn return sStatic.mCategories.size(); 11039a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 11049a1de308cea2d160778fd977825f10a07b49d738Adam Powell 11059a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 11069a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Return the {@link MediaRouter.RouteCategory category} at the given index. 11079a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Valid indices are in the range [0-getCategoryCount). 11089a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 11099a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param index which category to return 11109a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @return the category at index 11119a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 11129a1de308cea2d160778fd977825f10a07b49d738Adam Powell public RouteCategory getCategoryAt(int index) { 1113b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn return sStatic.mCategories.get(index); 11149a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 11159a1de308cea2d160778fd977825f10a07b49d738Adam Powell 11169a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 11179a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Return the number of {@link MediaRouter.RouteInfo routes} currently known 11189a1de308cea2d160778fd977825f10a07b49d738Adam Powell * to this MediaRouter. 11199a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 11209a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @return the number of routes tracked by this router 11219a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 11229a1de308cea2d160778fd977825f10a07b49d738Adam Powell public int getRouteCount() { 1123b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn return sStatic.mRoutes.size(); 11249a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 11259a1de308cea2d160778fd977825f10a07b49d738Adam Powell 11269a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 11279a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Return the route at the specified index. 11289a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 11299a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param index index of the route to return 11309a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @return the route at index 11319a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 11329a1de308cea2d160778fd977825f10a07b49d738Adam Powell public RouteInfo getRouteAt(int index) { 1133b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn return sStatic.mRoutes.get(index); 1134b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn } 1135b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn 1136b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn static int getRouteCountStatic() { 1137b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn return sStatic.mRoutes.size(); 1138b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn } 1139b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn 1140b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn static RouteInfo getRouteAtStatic(int index) { 1141b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn return sStatic.mRoutes.get(index); 11429a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 11439a1de308cea2d160778fd977825f10a07b49d738Adam Powell 11449a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 11459a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Create a new user route that may be modified and registered for use by the application. 11469a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 11479a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param category The category the new route will belong to 11489a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @return A new UserRouteInfo for use by the application 11499a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 11509a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @see #addUserRoute(UserRouteInfo) 11519a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @see #removeUserRoute(UserRouteInfo) 115269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * @see #createRouteCategory(CharSequence, boolean) 11539a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 11549a1de308cea2d160778fd977825f10a07b49d738Adam Powell public UserRouteInfo createUserRoute(RouteCategory category) { 11559a1de308cea2d160778fd977825f10a07b49d738Adam Powell return new UserRouteInfo(category); 11569a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 11579a1de308cea2d160778fd977825f10a07b49d738Adam Powell 11589a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 11599a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Create a new route category. Each route must belong to a category. 11609a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 11619a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param name Name of the new category 11629a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param isGroupable true if routes in this category may be grouped with one another 11639a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @return the new RouteCategory 11649a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 11659a1de308cea2d160778fd977825f10a07b49d738Adam Powell public RouteCategory createRouteCategory(CharSequence name, boolean isGroupable) { 11669a1de308cea2d160778fd977825f10a07b49d738Adam Powell return new RouteCategory(name, ROUTE_TYPE_USER, isGroupable); 11679a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 11685d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik 11690d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell /** 11700d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * Create a new route category. Each route must belong to a category. 11710d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * 11720d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * @param nameResId Resource ID of the name of the new category 11730d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * @param isGroupable true if routes in this category may be grouped with one another 11740d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * @return the new RouteCategory 11750d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell */ 11760d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public RouteCategory createRouteCategory(int nameResId, boolean isGroupable) { 11770d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell return new RouteCategory(nameResId, ROUTE_TYPE_USER, isGroupable); 11780d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell } 11799a1de308cea2d160778fd977825f10a07b49d738Adam Powell 118069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown /** 118169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * Rebinds the media router to handle routes that belong to the specified user. 118269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * Requires the interact across users permission to access the routes of another user. 118369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * <p> 118469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * This method is a complete hack to work around the singleton nature of the 118569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * media router when running inside of singleton processes like QuickSettings. 118669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * This mechanism should be burned to the ground when MediaRouter is redesigned. 118769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * Ideally the current user would be pulled from the Context but we need to break 118869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * down MediaRouter.Static before we can get there. 118969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * </p> 119069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * 119169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * @hide 119269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown */ 119369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public void rebindAsUser(int userId) { 119469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown sStatic.rebindAsUser(userId); 119569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 119669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 1197b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn static void updateRoute(final RouteInfo info) { 11989a1de308cea2d160778fd977825f10a07b49d738Adam Powell dispatchRouteChanged(info); 11999a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 12009a1de308cea2d160778fd977825f10a07b49d738Adam Powell 1201b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn static void dispatchRouteSelected(int type, RouteInfo info) { 120239d5c6172503620ac3761148adac5fd7fa20d02dAdam Powell for (CallbackInfo cbi : sStatic.mCallbacks) { 120366f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown if (cbi.filterRouteEvent(info)) { 1204b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn cbi.cb.onRouteSelected(cbi.router, type, info); 12059a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 12069a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 12079a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 12089a1de308cea2d160778fd977825f10a07b49d738Adam Powell 1209b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn static void dispatchRouteUnselected(int type, RouteInfo info) { 121039d5c6172503620ac3761148adac5fd7fa20d02dAdam Powell for (CallbackInfo cbi : sStatic.mCallbacks) { 121166f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown if (cbi.filterRouteEvent(info)) { 1212b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn cbi.cb.onRouteUnselected(cbi.router, type, info); 12139a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 12149a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 12159a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 12169a1de308cea2d160778fd977825f10a07b49d738Adam Powell 1217b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn static void dispatchRouteChanged(RouteInfo info) { 1218af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown dispatchRouteChanged(info, info.mSupportedTypes); 1219af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown } 1220af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown 1221af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown static void dispatchRouteChanged(RouteInfo info, int oldSupportedTypes) { 122218687b7a275b3782e63d52cdbe8ee9df191046e7Jae Seo Log.v(TAG, "Dispatching route change: " + info); 1223af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown final int newSupportedTypes = info.mSupportedTypes; 122439d5c6172503620ac3761148adac5fd7fa20d02dAdam Powell for (CallbackInfo cbi : sStatic.mCallbacks) { 1225af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown // Reconstruct some of the history for callbacks that may not have observed 1226af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown // all of the events needed to correctly interpret the current state. 1227af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown // FIXME: This is a strong signal that we should deprecate route type filtering 1228af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown // completely in the future because it can lead to inconsistencies in 1229af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown // applications. 1230af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown final boolean oldVisibility = cbi.filterRouteEvent(oldSupportedTypes); 1231af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown final boolean newVisibility = cbi.filterRouteEvent(newSupportedTypes); 1232af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown if (!oldVisibility && newVisibility) { 1233af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown cbi.cb.onRouteAdded(cbi.router, info); 1234af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown if (info.isSelected()) { 1235af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown cbi.cb.onRouteSelected(cbi.router, newSupportedTypes, info); 1236af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown } 1237af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown } 1238af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown if (oldVisibility || newVisibility) { 1239b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn cbi.cb.onRouteChanged(cbi.router, info); 12409a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 1241af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown if (oldVisibility && !newVisibility) { 1242af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown if (info.isSelected()) { 1243af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown cbi.cb.onRouteUnselected(cbi.router, oldSupportedTypes, info); 1244af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown } 1245af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown cbi.cb.onRouteRemoved(cbi.router, info); 1246af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown } 12479a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 12489a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 12499a1de308cea2d160778fd977825f10a07b49d738Adam Powell 1250b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn static void dispatchRouteAdded(RouteInfo info) { 125139d5c6172503620ac3761148adac5fd7fa20d02dAdam Powell for (CallbackInfo cbi : sStatic.mCallbacks) { 125266f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown if (cbi.filterRouteEvent(info)) { 1253b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn cbi.cb.onRouteAdded(cbi.router, info); 12549a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 12559a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 12569a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 12579a1de308cea2d160778fd977825f10a07b49d738Adam Powell 1258b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn static void dispatchRouteRemoved(RouteInfo info) { 125939d5c6172503620ac3761148adac5fd7fa20d02dAdam Powell for (CallbackInfo cbi : sStatic.mCallbacks) { 126066f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown if (cbi.filterRouteEvent(info)) { 1261b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn cbi.cb.onRouteRemoved(cbi.router, info); 12629a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 12639a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 12649a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 12659a1de308cea2d160778fd977825f10a07b49d738Adam Powell 1266b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn static void dispatchRouteGrouped(RouteInfo info, RouteGroup group, int index) { 126739d5c6172503620ac3761148adac5fd7fa20d02dAdam Powell for (CallbackInfo cbi : sStatic.mCallbacks) { 126866f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown if (cbi.filterRouteEvent(group)) { 1269b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn cbi.cb.onRouteGrouped(cbi.router, info, group, index); 1270d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell } 1271d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell } 1272d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell } 1273d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell 1274b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn static void dispatchRouteUngrouped(RouteInfo info, RouteGroup group) { 127539d5c6172503620ac3761148adac5fd7fa20d02dAdam Powell for (CallbackInfo cbi : sStatic.mCallbacks) { 127666f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown if (cbi.filterRouteEvent(group)) { 1277b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn cbi.cb.onRouteUngrouped(cbi.router, info, group); 12789a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 12799a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 12809a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 12819a1de308cea2d160778fd977825f10a07b49d738Adam Powell 12828e37a85bf3dc39519942698dc90a3951306b934bAdam Powell static void dispatchRouteVolumeChanged(RouteInfo info) { 12838e37a85bf3dc39519942698dc90a3951306b934bAdam Powell for (CallbackInfo cbi : sStatic.mCallbacks) { 128466f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown if (cbi.filterRouteEvent(info)) { 12858e37a85bf3dc39519942698dc90a3951306b934bAdam Powell cbi.cb.onRouteVolumeChanged(cbi.router, info); 12868e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 12878e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 12888e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 12898e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 129092130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown static void dispatchRoutePresentationDisplayChanged(RouteInfo info) { 129192130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown for (CallbackInfo cbi : sStatic.mCallbacks) { 129266f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown if (cbi.filterRouteEvent(info)) { 129392130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown cbi.cb.onRoutePresentationDisplayChanged(cbi.router, info); 129492130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown } 129592130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown } 129692130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown } 129792130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown 12988e37a85bf3dc39519942698dc90a3951306b934bAdam Powell static void systemVolumeChanged(int newValue) { 12998e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final RouteInfo selectedRoute = sStatic.mSelectedRoute; 13008e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (selectedRoute == null) return; 13018e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 13028e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (selectedRoute == sStatic.mBluetoothA2dpRoute || 1303705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell selectedRoute == sStatic.mDefaultAudioVideo) { 13048e37a85bf3dc39519942698dc90a3951306b934bAdam Powell dispatchRouteVolumeChanged(selectedRoute); 13058e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } else if (sStatic.mBluetoothA2dpRoute != null) { 1306fa6f70e225a7370c1ecb21ee7076c9086ecb9e9aSungsoo try { 1307fa6f70e225a7370c1ecb21ee7076c9086ecb9e9aSungsoo dispatchRouteVolumeChanged(sStatic.mAudioService.isBluetoothA2dpOn() ? 1308fa6f70e225a7370c1ecb21ee7076c9086ecb9e9aSungsoo sStatic.mBluetoothA2dpRoute : sStatic.mDefaultAudioVideo); 1309fa6f70e225a7370c1ecb21ee7076c9086ecb9e9aSungsoo } catch (RemoteException e) { 1310fa6f70e225a7370c1ecb21ee7076c9086ecb9e9aSungsoo Log.e(TAG, "Error checking Bluetooth A2DP state to report volume change", e); 1311fa6f70e225a7370c1ecb21ee7076c9086ecb9e9aSungsoo } 13128e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } else { 1313705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell dispatchRouteVolumeChanged(sStatic.mDefaultAudioVideo); 1314705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1315705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1316705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 131775af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown static void updateWifiDisplayStatus(WifiDisplayStatus status) { 131875af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown WifiDisplay[] displays; 1319615e413a90ff5898d8c458ebc9649ca95fa9fd98Adam Powell WifiDisplay activeDisplay; 132075af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown if (status.getFeatureState() == WifiDisplayStatus.FEATURE_STATE_ON) { 132175af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown displays = status.getDisplays(); 132275af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown activeDisplay = status.getActiveDisplay(); 1323af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown 1324af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown // Only the system is able to connect to wifi display routes. 1325af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown // The display manager will enforce this with a permission check but it 1326af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown // still publishes information about all available displays. 1327af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown // Filter the list down to just the active display. 1328af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown if (!sStatic.mCanConfigureWifiDisplays) { 1329af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown if (activeDisplay != null) { 1330af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown displays = new WifiDisplay[] { activeDisplay }; 1331af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown } else { 1332af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown displays = WifiDisplay.EMPTY_ARRAY; 1333af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown } 1334af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown } 1335615e413a90ff5898d8c458ebc9649ca95fa9fd98Adam Powell } else { 133675af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown displays = WifiDisplay.EMPTY_ARRAY; 1337615e413a90ff5898d8c458ebc9649ca95fa9fd98Adam Powell activeDisplay = null; 1338615e413a90ff5898d8c458ebc9649ca95fa9fd98Adam Powell } 1339ce468a35b388ca46578934706b38dbae94941643Jeff Brown String activeDisplayAddress = activeDisplay != null ? 1340ce468a35b388ca46578934706b38dbae94941643Jeff Brown activeDisplay.getDeviceAddress() : null; 1341705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 134275af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown // Add or update routes. 134375af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown for (int i = 0; i < displays.length; i++) { 134475af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown final WifiDisplay d = displays[i]; 134575af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown if (shouldShowWifiDisplay(d, activeDisplay)) { 1346ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang RouteInfo route = findWifiDisplayRoute(d); 1347ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang if (route == null) { 134875af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown route = makeWifiDisplayRoute(d, status); 1349ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang addRouteStatic(route); 1350ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang } else { 1351ce468a35b388ca46578934706b38dbae94941643Jeff Brown String address = d.getDeviceAddress(); 1352ce468a35b388ca46578934706b38dbae94941643Jeff Brown boolean disconnected = !address.equals(activeDisplayAddress) 1353ce468a35b388ca46578934706b38dbae94941643Jeff Brown && address.equals(sStatic.mPreviousActiveWifiDisplayAddress); 1354ce468a35b388ca46578934706b38dbae94941643Jeff Brown updateWifiDisplayRoute(route, d, status, disconnected); 1355ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang } 1356ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang if (d.equals(activeDisplay)) { 135769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown selectRouteStatic(route.getSupportedTypes(), route, false); 1358ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang } 13592ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell } 1360705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 136175af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown 136275af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown // Remove stale routes. 136375af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown for (int i = sStatic.mRoutes.size(); i-- > 0; ) { 136475af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown RouteInfo route = sStatic.mRoutes.get(i); 136575af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown if (route.mDeviceAddress != null) { 136675af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown WifiDisplay d = findWifiDisplay(displays, route.mDeviceAddress); 136775af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown if (d == null || !shouldShowWifiDisplay(d, activeDisplay)) { 136875af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown removeRouteStatic(route); 1369ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang } 1370705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1371705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1372ce468a35b388ca46578934706b38dbae94941643Jeff Brown 1373ce468a35b388ca46578934706b38dbae94941643Jeff Brown // Remember the current active wifi display address so that we can infer disconnections. 1374ce468a35b388ca46578934706b38dbae94941643Jeff Brown // TODO: This hack will go away once all of this is moved into the media router service. 1375ce468a35b388ca46578934706b38dbae94941643Jeff Brown sStatic.mPreviousActiveWifiDisplayAddress = activeDisplayAddress; 137675af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown } 1377705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 137875af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown private static boolean shouldShowWifiDisplay(WifiDisplay d, WifiDisplay activeDisplay) { 137975af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown return d.isRemembered() || d.equals(activeDisplay); 1380705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1381705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 1382ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang static int getWifiDisplayStatusCode(WifiDisplay d, WifiDisplayStatus wfdStatus) { 138369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown int newStatus; 1384ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang if (wfdStatus.getScanState() == WifiDisplayStatus.SCAN_STATE_SCANNING) { 1385ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang newStatus = RouteInfo.STATUS_SCANNING; 1386ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang } else if (d.isAvailable()) { 1387ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang newStatus = d.canConnect() ? 1388ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang RouteInfo.STATUS_AVAILABLE: RouteInfo.STATUS_IN_USE; 1389705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } else { 1390705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell newStatus = RouteInfo.STATUS_NOT_AVAILABLE; 1391705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1392705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 1393ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang if (d.equals(wfdStatus.getActiveDisplay())) { 1394ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang final int activeState = wfdStatus.getActiveDisplayState(); 1395705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell switch (activeState) { 1396705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell case WifiDisplayStatus.DISPLAY_STATE_CONNECTED: 139769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown newStatus = RouteInfo.STATUS_CONNECTED; 1398705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell break; 1399705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell case WifiDisplayStatus.DISPLAY_STATE_CONNECTING: 1400705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell newStatus = RouteInfo.STATUS_CONNECTING; 1401705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell break; 1402705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell case WifiDisplayStatus.DISPLAY_STATE_NOT_CONNECTED: 1403705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell Log.e(TAG, "Active display is not connected!"); 1404705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell break; 1405705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1406705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1407705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 1408ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang return newStatus; 1409ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang } 1410ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang 1411ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang static boolean isWifiDisplayEnabled(WifiDisplay d, WifiDisplayStatus wfdStatus) { 1412ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang return d.isAvailable() && (d.canConnect() || d.equals(wfdStatus.getActiveDisplay())); 1413ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang } 1414ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang 1415ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang static RouteInfo makeWifiDisplayRoute(WifiDisplay display, WifiDisplayStatus wfdStatus) { 1416ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang final RouteInfo newRoute = new RouteInfo(sStatic.mSystemCategory); 1417ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang newRoute.mDeviceAddress = display.getDeviceAddress(); 141869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown newRoute.mSupportedTypes = ROUTE_TYPE_LIVE_AUDIO | ROUTE_TYPE_LIVE_VIDEO 141969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown | ROUTE_TYPE_REMOTE_DISPLAY; 1420ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang newRoute.mVolumeHandling = RouteInfo.PLAYBACK_VOLUME_FIXED; 1421ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang newRoute.mPlaybackType = RouteInfo.PLAYBACK_TYPE_REMOTE; 1422ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang 142339ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown newRoute.setRealStatusCode(getWifiDisplayStatusCode(display, wfdStatus)); 1424ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang newRoute.mEnabled = isWifiDisplayEnabled(display, wfdStatus); 1425ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang newRoute.mName = display.getFriendlyDisplayName(); 1426ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang newRoute.mDescription = sStatic.mResources.getText( 1427ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang com.android.internal.R.string.wireless_display_route_description); 14285830b0b33618940d65197cec99d697b21908fec8Chong Zhang newRoute.updatePresentationDisplay(); 14299dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang newRoute.mDeviceType = RouteInfo.DEVICE_TYPE_TV; 1430ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang return newRoute; 1431ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang } 1432ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang 1433ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang private static void updateWifiDisplayRoute( 1434ce468a35b388ca46578934706b38dbae94941643Jeff Brown RouteInfo route, WifiDisplay display, WifiDisplayStatus wfdStatus, 1435ce468a35b388ca46578934706b38dbae94941643Jeff Brown boolean disconnected) { 1436ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang boolean changed = false; 14372444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown final String newName = display.getFriendlyDisplayName(); 14382444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown if (!route.getName().equals(newName)) { 1439705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell route.mName = newName; 1440705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell changed = true; 1441705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1442705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 1443ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang boolean enabled = isWifiDisplayEnabled(display, wfdStatus); 1444ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang changed |= route.mEnabled != enabled; 1445ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang route.mEnabled = enabled; 1446705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 144739ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown changed |= route.setRealStatusCode(getWifiDisplayStatusCode(display, wfdStatus)); 1448705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 1449705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell if (changed) { 1450705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell dispatchRouteChanged(route); 1451705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1452705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 1453ce468a35b388ca46578934706b38dbae94941643Jeff Brown if ((!enabled || disconnected) && route.isSelected()) { 1454705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell // Oops, no longer available. Reselect the default. 145569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown selectDefaultRouteStatic(); 1456705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1457705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1458705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 145975af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown private static WifiDisplay findWifiDisplay(WifiDisplay[] displays, String deviceAddress) { 1460705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell for (int i = 0; i < displays.length; i++) { 146175af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown final WifiDisplay d = displays[i]; 146275af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown if (d.getDeviceAddress().equals(deviceAddress)) { 146375af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown return d; 1464705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1465705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1466705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell return null; 1467705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1468705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 1469705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell private static RouteInfo findWifiDisplayRoute(WifiDisplay d) { 1470705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell final int count = sStatic.mRoutes.size(); 1471705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell for (int i = 0; i < count; i++) { 1472705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell final RouteInfo info = sStatic.mRoutes.get(i); 1473705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell if (d.getDeviceAddress().equals(info.mDeviceAddress)) { 1474705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell return info; 1475705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1476705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1477705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell return null; 14788e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 14798e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 14809a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 14819a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Information about a media route. 14829a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 1483b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn public static class RouteInfo { 14849a1de308cea2d160778fd977825f10a07b49d738Adam Powell CharSequence mName; 14850d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell int mNameResId; 148656d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown CharSequence mDescription; 14879a1de308cea2d160778fd977825f10a07b49d738Adam Powell private CharSequence mStatus; 14889a1de308cea2d160778fd977825f10a07b49d738Adam Powell int mSupportedTypes; 14899dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang int mDeviceType; 14909a1de308cea2d160778fd977825f10a07b49d738Adam Powell RouteGroup mGroup; 14919a1de308cea2d160778fd977825f10a07b49d738Adam Powell final RouteCategory mCategory; 1492ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell Drawable mIcon; 14931357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi // playback information 14941357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi int mPlaybackType = PLAYBACK_TYPE_LOCAL; 14951357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi int mVolumeMax = RemoteControlClient.DEFAULT_PLAYBACK_VOLUME; 14961357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi int mVolume = RemoteControlClient.DEFAULT_PLAYBACK_VOLUME; 14971357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi int mVolumeHandling = RemoteControlClient.DEFAULT_PLAYBACK_VOLUME_HANDLING; 14981357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi int mPlaybackStream = AudioManager.STREAM_MUSIC; 14991357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi VolumeCallbackInfo mVcb; 150092130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown Display mPresentationDisplay; 15015830b0b33618940d65197cec99d697b21908fec8Chong Zhang int mPresentationDisplayId = -1; 15029a1de308cea2d160778fd977825f10a07b49d738Adam Powell 1503705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell String mDeviceAddress; 1504705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell boolean mEnabled = true; 1505705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 150669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // An id by which the route is known to the media router service. 150769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Null if this route only exists as an artifact within this process. 150869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown String mGlobalRouteId; 150969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 1510705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell // A predetermined connection status that can override mStatus 151139ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown private int mRealStatusCode; 151239ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown private int mResolvedStatusCode; 1513705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 15142ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell /** @hide */ public static final int STATUS_NONE = 0; 15152ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell /** @hide */ public static final int STATUS_SCANNING = 1; 15162ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell /** @hide */ public static final int STATUS_CONNECTING = 2; 15172ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell /** @hide */ public static final int STATUS_AVAILABLE = 3; 15182ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell /** @hide */ public static final int STATUS_NOT_AVAILABLE = 4; 1519ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang /** @hide */ public static final int STATUS_IN_USE = 5; 152069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown /** @hide */ public static final int STATUS_CONNECTED = 6; 1521705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 15229dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang /** @hide */ 15239dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang @IntDef({DEVICE_TYPE_UNKNOWN, DEVICE_TYPE_TV, DEVICE_TYPE_SPEAKER, DEVICE_TYPE_BLUETOOTH}) 15249dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang @Retention(RetentionPolicy.SOURCE) 15259dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang public @interface DeviceType {} 15269dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang 15279dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang /** 15289dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang * The default receiver device type of the route indicating the type is unknown. 15299dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang * 15309dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang * @see #getDeviceType 15319dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang */ 15329dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang public static final int DEVICE_TYPE_UNKNOWN = 0; 15339dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang 15349dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang /** 15359dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang * A receiver device type of the route indicating the presentation of the media is happening 15369dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang * on a TV. 15379dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang * 15389dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang * @see #getDeviceType 15399dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang */ 15409dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang public static final int DEVICE_TYPE_TV = 1; 15419dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang 15429dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang /** 15439dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang * A receiver device type of the route indicating the presentation of the media is happening 15449dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang * on a speaker. 15459dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang * 15469dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang * @see #getDeviceType 15479dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang */ 15489dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang public static final int DEVICE_TYPE_SPEAKER = 2; 15499dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang 15509dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang /** 15519dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang * A receiver device type of the route indicating the presentation of the media is happening 15529dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang * on a bluetooth device such as a bluetooth speaker. 15539dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang * 15549dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang * @see #getDeviceType 15559dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang */ 15569dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang public static final int DEVICE_TYPE_BLUETOOTH = 3; 15579dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang 1558b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell private Object mTag; 1559b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell 15607c090d54e2c0eb5309d3f7dc131e137d9c986793Insun Kang /** @hide */ 15617c090d54e2c0eb5309d3f7dc131e137d9c986793Insun Kang @IntDef({PLAYBACK_TYPE_LOCAL, PLAYBACK_TYPE_REMOTE}) 15627c090d54e2c0eb5309d3f7dc131e137d9c986793Insun Kang @Retention(RetentionPolicy.SOURCE) 15637c090d54e2c0eb5309d3f7dc131e137d9c986793Insun Kang public @interface PlaybackType {} 15647c090d54e2c0eb5309d3f7dc131e137d9c986793Insun Kang 15651357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 15661357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * The default playback type, "local", indicating the presentation of the media is happening 1567bc4cf00dc5bf6e0e3c01206d5c46e64306df260aJohn Spurlock * on the same device (e.g. a phone, a tablet) as where it is controlled from. 156869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * @see #getPlaybackType() 15691357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 15701357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public final static int PLAYBACK_TYPE_LOCAL = 0; 15717c090d54e2c0eb5309d3f7dc131e137d9c986793Insun Kang 15721357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 15731357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * A playback type indicating the presentation of the media is happening on 1574bc4cf00dc5bf6e0e3c01206d5c46e64306df260aJohn Spurlock * a different device (i.e. the remote device) than where it is controlled from. 157569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * @see #getPlaybackType() 15761357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 15771357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public final static int PLAYBACK_TYPE_REMOTE = 1; 15787c090d54e2c0eb5309d3f7dc131e137d9c986793Insun Kang 15797c090d54e2c0eb5309d3f7dc131e137d9c986793Insun Kang /** @hide */ 15807c090d54e2c0eb5309d3f7dc131e137d9c986793Insun Kang @IntDef({PLAYBACK_VOLUME_FIXED,PLAYBACK_VOLUME_VARIABLE}) 15817c090d54e2c0eb5309d3f7dc131e137d9c986793Insun Kang @Retention(RetentionPolicy.SOURCE) 15827c090d54e2c0eb5309d3f7dc131e137d9c986793Insun Kang private @interface PlaybackVolume {} 15837c090d54e2c0eb5309d3f7dc131e137d9c986793Insun Kang 15841357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 1585bc4cf00dc5bf6e0e3c01206d5c46e64306df260aJohn Spurlock * Playback information indicating the playback volume is fixed, i.e. it cannot be 15861357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * controlled from this object. An example of fixed playback volume is a remote player, 15871357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * playing over HDMI where the user prefers to control the volume on the HDMI sink, rather 15881357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * than attenuate at the source. 158969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * @see #getVolumeHandling() 15901357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 15911357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public final static int PLAYBACK_VOLUME_FIXED = 0; 15921357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 15931357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * Playback information indicating the playback volume is variable and can be controlled 15941357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * from this object. 159569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * @see #getVolumeHandling() 15961357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 15971357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public final static int PLAYBACK_VOLUME_VARIABLE = 1; 15981357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 15999a1de308cea2d160778fd977825f10a07b49d738Adam Powell RouteInfo(RouteCategory category) { 16009a1de308cea2d160778fd977825f10a07b49d738Adam Powell mCategory = category; 16019dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang mDeviceType = DEVICE_TYPE_UNKNOWN; 16029a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 16039a1de308cea2d160778fd977825f10a07b49d738Adam Powell 16049a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 160556d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * Gets the user-visible name of the route. 160656d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * <p> 160756d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * The route name identifies the destination represented by the route. 160856d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * It may be a user-supplied name, an alias, or device serial number. 160956d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * </p> 161056d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * 161156d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * @return The user-visible name of a media route. This is the string presented 16129a1de308cea2d160778fd977825f10a07b49d738Adam Powell * to users who may select this as the active route. 16139a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 16149a1de308cea2d160778fd977825f10a07b49d738Adam Powell public CharSequence getName() { 16150d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell return getName(sStatic.mResources); 16160d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell } 161756d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown 16180d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell /** 161956d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * Return the properly localized/resource user-visible name of this route. 162056d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * <p> 162156d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * The route name identifies the destination represented by the route. 162256d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * It may be a user-supplied name, an alias, or device serial number. 162356d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * </p> 162456d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * 16250d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * @param context Context used to resolve the correct configuration to load 162656d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * @return The user-visible name of a media route. This is the string presented 16270d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * to users who may select this as the active route. 16280d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell */ 16290d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public CharSequence getName(Context context) { 16300d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell return getName(context.getResources()); 16310d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell } 163256d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown 16330d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell CharSequence getName(Resources res) { 16340d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell if (mNameResId != 0) { 1635eadd6d2329972129c96dee390a8b786b37313d17Hyundo Moon return res.getText(mNameResId); 16360d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell } 16379a1de308cea2d160778fd977825f10a07b49d738Adam Powell return mName; 16389a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 16399a1de308cea2d160778fd977825f10a07b49d738Adam Powell 16409a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 164156d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * Gets the user-visible description of the route. 164256d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * <p> 164356d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * The route description describes the kind of destination represented by the route. 164456d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * It may be a user-supplied string, a model number or brand of device. 164556d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * </p> 164656d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * 164756d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * @return The description of the route, or null if none. 164856d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown */ 164956d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown public CharSequence getDescription() { 165056d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown return mDescription; 165156d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown } 165256d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown 165356d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown /** 165456d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * @return The user-visible status for a media route. This may include a description 16559a1de308cea2d160778fd977825f10a07b49d738Adam Powell * of the currently playing media, if available. 16569a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 16579a1de308cea2d160778fd977825f10a07b49d738Adam Powell public CharSequence getStatus() { 16589a1de308cea2d160778fd977825f10a07b49d738Adam Powell return mStatus; 16599a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 16609a1de308cea2d160778fd977825f10a07b49d738Adam Powell 16619a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 1662705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell * Set this route's status by predetermined status code. If the caller 1663705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell * should dispatch a route changed event this call will return true; 1664705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell */ 166539ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown boolean setRealStatusCode(int statusCode) { 166639ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown if (mRealStatusCode != statusCode) { 166739ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown mRealStatusCode = statusCode; 166839ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown return resolveStatusCode(); 166939ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown } 167039ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown return false; 167139ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown } 167239ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown 167339ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown /** 167439ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown * Resolves the status code whenever the real status code or selection state 167539ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown * changes. 167639ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown */ 167739ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown boolean resolveStatusCode() { 167839ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown int statusCode = mRealStatusCode; 167939ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown if (isSelected()) { 1680705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell switch (statusCode) { 168139ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown // If the route is selected and its status appears to be between states 168239ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown // then report it as connecting even though it has not yet had a chance 168339ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown // to officially move into the CONNECTING state. Note that routes in 168439ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown // the NONE state are assumed to not require an explicit connection 168539ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown // lifecycle whereas those that are AVAILABLE are assumed to have 168639ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown // to eventually proceed to CONNECTED. 1687705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell case STATUS_AVAILABLE: 168839ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown case STATUS_SCANNING: 168939ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown statusCode = STATUS_CONNECTING; 169069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown break; 1691705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1692705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 169339ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown if (mResolvedStatusCode == statusCode) { 169439ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown return false; 169539ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown } 169639ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown 169739ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown mResolvedStatusCode = statusCode; 169839ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown int resId; 169939ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown switch (statusCode) { 170039ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown case STATUS_SCANNING: 170139ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown resId = com.android.internal.R.string.media_route_status_scanning; 170239ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown break; 170339ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown case STATUS_CONNECTING: 170439ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown resId = com.android.internal.R.string.media_route_status_connecting; 170539ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown break; 170639ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown case STATUS_AVAILABLE: 170739ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown resId = com.android.internal.R.string.media_route_status_available; 170839ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown break; 170939ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown case STATUS_NOT_AVAILABLE: 171039ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown resId = com.android.internal.R.string.media_route_status_not_available; 171139ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown break; 171239ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown case STATUS_IN_USE: 171339ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown resId = com.android.internal.R.string.media_route_status_in_use; 171439ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown break; 171539ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown case STATUS_CONNECTED: 171639ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown case STATUS_NONE: 171739ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown default: 171839ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown resId = 0; 171939ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown break; 172039ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown } 172139ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown mStatus = resId != 0 ? sStatic.mResources.getText(resId) : null; 172239ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown return true; 1723705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1724705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 1725705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell /** 17262ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell * @hide 17272ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell */ 17282ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell public int getStatusCode() { 172939ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown return mResolvedStatusCode; 17302ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell } 17312ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell 17322ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell /** 17339a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @return A media type flag set describing which types this route supports. 17349a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 17359a1de308cea2d160778fd977825f10a07b49d738Adam Powell public int getSupportedTypes() { 17369a1de308cea2d160778fd977825f10a07b49d738Adam Powell return mSupportedTypes; 17379a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 17389a1de308cea2d160778fd977825f10a07b49d738Adam Powell 17399dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang /** 17409dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang * Gets the type of the receiver device associated with this route. 17419dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang * 17429dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang * @return The type of the receiver device associated with this route: 17439dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang * {@link #DEVICE_TYPE_BLUETOOTH}, {@link #DEVICE_TYPE_TV}, {@link #DEVICE_TYPE_SPEAKER}, 17449dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang * or {@link #DEVICE_TYPE_UNKNOWN}. 17459dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang */ 17469dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang @DeviceType 17479dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang public int getDeviceType() { 17489dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang return mDeviceType; 17499dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang } 17509dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang 17510abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown /** @hide */ 17520abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown public boolean matchesTypes(int types) { 17530abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown return (mSupportedTypes & types) != 0; 17540abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown } 17550abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown 17569a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 17579a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @return The group that this route belongs to. 17589a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 17599a1de308cea2d160778fd977825f10a07b49d738Adam Powell public RouteGroup getGroup() { 17609a1de308cea2d160778fd977825f10a07b49d738Adam Powell return mGroup; 17619a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 17629a1de308cea2d160778fd977825f10a07b49d738Adam Powell 17639a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 17649a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @return the category this route belongs to. 17659a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 17669a1de308cea2d160778fd977825f10a07b49d738Adam Powell public RouteCategory getCategory() { 17679a1de308cea2d160778fd977825f10a07b49d738Adam Powell return mCategory; 17689a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 17699a1de308cea2d160778fd977825f10a07b49d738Adam Powell 1770ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell /** 1771ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * Get the icon representing this route. 1772ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * This icon will be used in picker UIs if available. 1773ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * 1774ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * @return the icon representing this route or null if no icon is available 1775ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell */ 1776ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell public Drawable getIconDrawable() { 1777ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell return mIcon; 1778ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell } 1779ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell 1780b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell /** 1781b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell * Set an application-specific tag object for this route. 1782b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell * The application may use this to store arbitrary data associated with the 1783b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell * route for internal tracking. 1784b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell * 1785b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell * <p>Note that the lifespan of a route may be well past the lifespan of 1786b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell * an Activity or other Context; take care that objects you store here 1787b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell * will not keep more data in memory alive than you intend.</p> 1788b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell * 1789b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell * @param tag Arbitrary, app-specific data for this route to hold for later use 1790b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell */ 1791b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell public void setTag(Object tag) { 1792b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell mTag = tag; 1793130b4572d1f3df702e5b296a655d15a41f6d4c66Adam Powell routeUpdated(); 1794b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell } 1795b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell 1796b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell /** 1797b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell * @return The tag object previously set by the application 1798b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell * @see #setTag(Object) 1799b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell */ 1800b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell public Object getTag() { 1801b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell return mTag; 1802b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell } 1803b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell 18041357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 18051357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @return the type of playback associated with this route 18061357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @see UserRouteInfo#setPlaybackType(int) 18071357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 18087c090d54e2c0eb5309d3f7dc131e137d9c986793Insun Kang @PlaybackType 18091357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public int getPlaybackType() { 18101357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi return mPlaybackType; 18111357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 18121357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 18131357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 18141357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @return the stream over which the playback associated with this route is performed 18151357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @see UserRouteInfo#setPlaybackStream(int) 18161357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 18171357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public int getPlaybackStream() { 18181357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi return mPlaybackStream; 18191357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 18201357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 18211357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 18228e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * Return the current volume for this route. Depending on the route, this may only 18238e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * be valid if the route is currently selected. 18248e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * 18251357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @return the volume at which the playback associated with this route is performed 18261357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @see UserRouteInfo#setVolume(int) 18271357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 18281357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public int getVolume() { 18291357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi if (mPlaybackType == PLAYBACK_TYPE_LOCAL) { 18301357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi int vol = 0; 18311357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi try { 18321357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi vol = sStatic.mAudioService.getStreamVolume(mPlaybackStream); 18331357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } catch (RemoteException e) { 18341357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi Log.e(TAG, "Error getting local stream volume", e); 18351357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 18361357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi return vol; 18371357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } else { 18381357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi return mVolume; 18391357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 18401357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 18411357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 18421357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 18438e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * Request a volume change for this route. 18448e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * @param volume value between 0 and getVolumeMax 18458e37a85bf3dc39519942698dc90a3951306b934bAdam Powell */ 18468e37a85bf3dc39519942698dc90a3951306b934bAdam Powell public void requestSetVolume(int volume) { 18478e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (mPlaybackType == PLAYBACK_TYPE_LOCAL) { 18488e37a85bf3dc39519942698dc90a3951306b934bAdam Powell try { 1849ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn sStatic.mAudioService.setStreamVolume(mPlaybackStream, volume, 0, 1850ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn ActivityThread.currentPackageName()); 18518e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } catch (RemoteException e) { 18528e37a85bf3dc39519942698dc90a3951306b934bAdam Powell Log.e(TAG, "Error setting local stream volume", e); 18538e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 18548e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } else { 185569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown sStatic.requestSetVolume(this, volume); 18568e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 18578e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 18588e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 18598e37a85bf3dc39519942698dc90a3951306b934bAdam Powell /** 18608e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * Request an incremental volume update for this route. 18618e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * @param direction Delta to apply to the current volume 18628e37a85bf3dc39519942698dc90a3951306b934bAdam Powell */ 18638e37a85bf3dc39519942698dc90a3951306b934bAdam Powell public void requestUpdateVolume(int direction) { 18648e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (mPlaybackType == PLAYBACK_TYPE_LOCAL) { 18658e37a85bf3dc39519942698dc90a3951306b934bAdam Powell try { 18668e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final int volume = 18678e37a85bf3dc39519942698dc90a3951306b934bAdam Powell Math.max(0, Math.min(getVolume() + direction, getVolumeMax())); 1868ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn sStatic.mAudioService.setStreamVolume(mPlaybackStream, volume, 0, 1869ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn ActivityThread.currentPackageName()); 18708e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } catch (RemoteException e) { 18718e37a85bf3dc39519942698dc90a3951306b934bAdam Powell Log.e(TAG, "Error setting local stream volume", e); 18728e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 18738e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } else { 187469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown sStatic.requestUpdateVolume(this, direction); 18758e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 18768e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 18778e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 18788e37a85bf3dc39519942698dc90a3951306b934bAdam Powell /** 18791357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @return the maximum volume at which the playback associated with this route is performed 18801357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @see UserRouteInfo#setVolumeMax(int) 18811357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 18821357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public int getVolumeMax() { 18831357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi if (mPlaybackType == PLAYBACK_TYPE_LOCAL) { 18841357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi int volMax = 0; 18851357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi try { 18861357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi volMax = sStatic.mAudioService.getStreamMaxVolume(mPlaybackStream); 18871357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } catch (RemoteException e) { 18881357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi Log.e(TAG, "Error getting local stream volume", e); 18891357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 18901357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi return volMax; 18911357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } else { 18921357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi return mVolumeMax; 18931357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 18941357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 18951357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 18961357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 18971357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @return how volume is handling on the route 18981357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @see UserRouteInfo#setVolumeHandling(int) 18991357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 19007c090d54e2c0eb5309d3f7dc131e137d9c986793Insun Kang @PlaybackVolume 19011357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public int getVolumeHandling() { 19021357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi return mVolumeHandling; 19031357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 19041357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 1905705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell /** 190692130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * Gets the {@link Display} that should be used by the application to show 190792130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * a {@link android.app.Presentation} on an external display when this route is selected. 190892130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * Depending on the route, this may only be valid if the route is currently 190992130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * selected. 191092130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * <p> 191192130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * The preferred presentation display may change independently of the route 191292130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * being selected or unselected. For example, the presentation display 191392130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * of the default system route may change when an external HDMI display is connected 191492130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * or disconnected even though the route itself has not changed. 191592130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * </p><p> 191692130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * This method may return null if there is no external display associated with 191792130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * the route or if the display is not ready to show UI yet. 191892130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * </p><p> 191992130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * The application should listen for changes to the presentation display 192092130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * using the {@link Callback#onRoutePresentationDisplayChanged} callback and 192192130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * show or dismiss its {@link android.app.Presentation} accordingly when the display 192292130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * becomes available or is removed. 192392130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * </p><p> 192492130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * This method only makes sense for {@link #ROUTE_TYPE_LIVE_VIDEO live video} routes. 192592130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * </p> 192692130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * 192792130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * @return The preferred presentation display to use when this route is 192892130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * selected or null if none. 192992130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * 193092130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * @see #ROUTE_TYPE_LIVE_VIDEO 193192130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * @see android.app.Presentation 193292130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown */ 193392130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown public Display getPresentationDisplay() { 193492130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown return mPresentationDisplay; 193592130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown } 193692130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown 19375830b0b33618940d65197cec99d697b21908fec8Chong Zhang boolean updatePresentationDisplay() { 19385830b0b33618940d65197cec99d697b21908fec8Chong Zhang Display display = choosePresentationDisplay(); 19395830b0b33618940d65197cec99d697b21908fec8Chong Zhang if (mPresentationDisplay != display) { 19405830b0b33618940d65197cec99d697b21908fec8Chong Zhang mPresentationDisplay = display; 19415830b0b33618940d65197cec99d697b21908fec8Chong Zhang return true; 19425830b0b33618940d65197cec99d697b21908fec8Chong Zhang } 19435830b0b33618940d65197cec99d697b21908fec8Chong Zhang return false; 19445830b0b33618940d65197cec99d697b21908fec8Chong Zhang } 19455830b0b33618940d65197cec99d697b21908fec8Chong Zhang 19465830b0b33618940d65197cec99d697b21908fec8Chong Zhang private Display choosePresentationDisplay() { 19475830b0b33618940d65197cec99d697b21908fec8Chong Zhang if ((mSupportedTypes & ROUTE_TYPE_LIVE_VIDEO) != 0) { 19485830b0b33618940d65197cec99d697b21908fec8Chong Zhang Display[] displays = sStatic.getAllPresentationDisplays(); 19495830b0b33618940d65197cec99d697b21908fec8Chong Zhang 19505830b0b33618940d65197cec99d697b21908fec8Chong Zhang // Ensure that the specified display is valid for presentations. 19515830b0b33618940d65197cec99d697b21908fec8Chong Zhang // This check will normally disallow the default display unless it was 19525830b0b33618940d65197cec99d697b21908fec8Chong Zhang // configured as a presentation display for some reason. 19535830b0b33618940d65197cec99d697b21908fec8Chong Zhang if (mPresentationDisplayId >= 0) { 19545830b0b33618940d65197cec99d697b21908fec8Chong Zhang for (Display display : displays) { 19555830b0b33618940d65197cec99d697b21908fec8Chong Zhang if (display.getDisplayId() == mPresentationDisplayId) { 19565830b0b33618940d65197cec99d697b21908fec8Chong Zhang return display; 19575830b0b33618940d65197cec99d697b21908fec8Chong Zhang } 19585830b0b33618940d65197cec99d697b21908fec8Chong Zhang } 19595830b0b33618940d65197cec99d697b21908fec8Chong Zhang return null; 19605830b0b33618940d65197cec99d697b21908fec8Chong Zhang } 19615830b0b33618940d65197cec99d697b21908fec8Chong Zhang 19625830b0b33618940d65197cec99d697b21908fec8Chong Zhang // Find the indicated Wifi display by its address. 19635830b0b33618940d65197cec99d697b21908fec8Chong Zhang if (mDeviceAddress != null) { 19645830b0b33618940d65197cec99d697b21908fec8Chong Zhang for (Display display : displays) { 19655830b0b33618940d65197cec99d697b21908fec8Chong Zhang if (display.getType() == Display.TYPE_WIFI 19665830b0b33618940d65197cec99d697b21908fec8Chong Zhang && mDeviceAddress.equals(display.getAddress())) { 19675830b0b33618940d65197cec99d697b21908fec8Chong Zhang return display; 19685830b0b33618940d65197cec99d697b21908fec8Chong Zhang } 19695830b0b33618940d65197cec99d697b21908fec8Chong Zhang } 19705830b0b33618940d65197cec99d697b21908fec8Chong Zhang return null; 19715830b0b33618940d65197cec99d697b21908fec8Chong Zhang } 19725830b0b33618940d65197cec99d697b21908fec8Chong Zhang 19735830b0b33618940d65197cec99d697b21908fec8Chong Zhang // For the default route, choose the first presentation display from the list. 19745830b0b33618940d65197cec99d697b21908fec8Chong Zhang if (this == sStatic.mDefaultAudioVideo && displays.length > 0) { 19755830b0b33618940d65197cec99d697b21908fec8Chong Zhang return displays[0]; 19765830b0b33618940d65197cec99d697b21908fec8Chong Zhang } 19775830b0b33618940d65197cec99d697b21908fec8Chong Zhang } 19785830b0b33618940d65197cec99d697b21908fec8Chong Zhang return null; 19795830b0b33618940d65197cec99d697b21908fec8Chong Zhang } 19805830b0b33618940d65197cec99d697b21908fec8Chong Zhang 198175af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown /** @hide */ 198275af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown public String getDeviceAddress() { 198375af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown return mDeviceAddress; 198475af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown } 198575af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown 198692130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown /** 1987a27b8fb4296c1271ddf5916843ddffda6764e65fJeff Brown * Returns true if this route is enabled and may be selected. 1988a27b8fb4296c1271ddf5916843ddffda6764e65fJeff Brown * 1989a27b8fb4296c1271ddf5916843ddffda6764e65fJeff Brown * @return True if this route is enabled. 1990705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell */ 1991705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell public boolean isEnabled() { 1992705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell return mEnabled; 1993705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1994705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 1995a27b8fb4296c1271ddf5916843ddffda6764e65fJeff Brown /** 1996a27b8fb4296c1271ddf5916843ddffda6764e65fJeff Brown * Returns true if the route is in the process of connecting and is not 1997a27b8fb4296c1271ddf5916843ddffda6764e65fJeff Brown * yet ready for use. 1998a27b8fb4296c1271ddf5916843ddffda6764e65fJeff Brown * 1999a27b8fb4296c1271ddf5916843ddffda6764e65fJeff Brown * @return True if this route is in the process of connecting. 2000a27b8fb4296c1271ddf5916843ddffda6764e65fJeff Brown */ 2001a27b8fb4296c1271ddf5916843ddffda6764e65fJeff Brown public boolean isConnecting() { 200239ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown return mResolvedStatusCode == STATUS_CONNECTING; 20030abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown } 20040abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown 20050abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown /** @hide */ 20060abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown public boolean isSelected() { 20070abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown return this == sStatic.mSelectedRoute; 20080abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown } 20090abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown 20100abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown /** @hide */ 20110abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown public boolean isDefault() { 20120abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown return this == sStatic.mDefaultAudioVideo; 20130abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown } 20140abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown 20150abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown /** @hide */ 20160abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown public void select() { 20170abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown selectRouteStatic(mSupportedTypes, this, true); 2018a27b8fb4296c1271ddf5916843ddffda6764e65fJeff Brown } 2019a27b8fb4296c1271ddf5916843ddffda6764e65fJeff Brown 20209a1de308cea2d160778fd977825f10a07b49d738Adam Powell void setStatusInt(CharSequence status) { 20219a1de308cea2d160778fd977825f10a07b49d738Adam Powell if (!status.equals(mStatus)) { 20229a1de308cea2d160778fd977825f10a07b49d738Adam Powell mStatus = status; 20239a1de308cea2d160778fd977825f10a07b49d738Adam Powell if (mGroup != null) { 20249a1de308cea2d160778fd977825f10a07b49d738Adam Powell mGroup.memberStatusChanged(this, status); 20259a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 20269a1de308cea2d160778fd977825f10a07b49d738Adam Powell routeUpdated(); 20279a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 20289a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 20299a1de308cea2d160778fd977825f10a07b49d738Adam Powell 20301357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi final IRemoteVolumeObserver.Stub mRemoteVolObserver = new IRemoteVolumeObserver.Stub() { 203169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown @Override 20321357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public void dispatchRemoteVolumeUpdate(final int direction, final int value) { 20331357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi sStatic.mHandler.post(new Runnable() { 20341357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi @Override 20351357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public void run() { 20361357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi if (mVcb != null) { 20371357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi if (direction != 0) { 20381357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi mVcb.vcb.onVolumeUpdateRequest(mVcb.route, direction); 20391357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } else { 20401357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi mVcb.vcb.onVolumeSetRequest(mVcb.route, value); 20411357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 20421357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 20431357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 20441357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi }); 20451357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 20461357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi }; 20471357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 20489a1de308cea2d160778fd977825f10a07b49d738Adam Powell void routeUpdated() { 20499a1de308cea2d160778fd977825f10a07b49d738Adam Powell updateRoute(this); 20509a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 20519a1de308cea2d160778fd977825f10a07b49d738Adam Powell 20529a1de308cea2d160778fd977825f10a07b49d738Adam Powell @Override 20539a1de308cea2d160778fd977825f10a07b49d738Adam Powell public String toString() { 2054d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell String supportedTypes = typesToString(getSupportedTypes()); 205592130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown return getClass().getSimpleName() + "{ name=" + getName() + 205656d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown ", description=" + getDescription() + 205792130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown ", status=" + getStatus() + 205892130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown ", category=" + getCategory() + 205992130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown ", supportedTypes=" + supportedTypes + 206069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown ", presentationDisplay=" + mPresentationDisplay + " }"; 20619a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 20629a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 20639a1de308cea2d160778fd977825f10a07b49d738Adam Powell 20649a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 20659a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Information about a route that the application may define and modify. 20668e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * A user route defaults to {@link RouteInfo#PLAYBACK_TYPE_REMOTE} and 20678e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * {@link RouteInfo#PLAYBACK_VOLUME_FIXED}. 20689a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 20699a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @see MediaRouter.RouteInfo 20709a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 2071b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn public static class UserRouteInfo extends RouteInfo { 2072ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell RemoteControlClient mRcc; 20735d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik SessionVolumeProvider mSvp; 20749a1de308cea2d160778fd977825f10a07b49d738Adam Powell 20759a1de308cea2d160778fd977825f10a07b49d738Adam Powell UserRouteInfo(RouteCategory category) { 20769a1de308cea2d160778fd977825f10a07b49d738Adam Powell super(category); 20779a1de308cea2d160778fd977825f10a07b49d738Adam Powell mSupportedTypes = ROUTE_TYPE_USER; 20788e37a85bf3dc39519942698dc90a3951306b934bAdam Powell mPlaybackType = PLAYBACK_TYPE_REMOTE; 20798e37a85bf3dc39519942698dc90a3951306b934bAdam Powell mVolumeHandling = PLAYBACK_VOLUME_FIXED; 20809a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 20819a1de308cea2d160778fd977825f10a07b49d738Adam Powell 20829a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 20839a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Set the user-visible name of this route. 20849a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param name Name to display to the user to describe this route 20859a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 20869a1de308cea2d160778fd977825f10a07b49d738Adam Powell public void setName(CharSequence name) { 2087eadd6d2329972129c96dee390a8b786b37313d17Hyundo Moon mNameResId = 0; 20889a1de308cea2d160778fd977825f10a07b49d738Adam Powell mName = name; 20899a1de308cea2d160778fd977825f10a07b49d738Adam Powell routeUpdated(); 20909a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 20915d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik 20920d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell /** 20930d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * Set the user-visible name of this route. 209456d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * <p> 209556d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * The route name identifies the destination represented by the route. 209656d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * It may be a user-supplied name, an alias, or device serial number. 209756d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * </p> 209856d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * 20990d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * @param resId Resource ID of the name to display to the user to describe this route 21000d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell */ 21010d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public void setName(int resId) { 21020d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell mNameResId = resId; 21030d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell mName = null; 21040d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell routeUpdated(); 21050d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell } 21069a1de308cea2d160778fd977825f10a07b49d738Adam Powell 21079a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 210856d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * Set the user-visible description of this route. 210956d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * <p> 211056d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * The route description describes the kind of destination represented by the route. 211156d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * It may be a user-supplied string, a model number or brand of device. 211256d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * </p> 211356d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * 211456d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * @param description The description of the route, or null if none. 211556d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown */ 211656d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown public void setDescription(CharSequence description) { 211756d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown mDescription = description; 211856d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown routeUpdated(); 211956d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown } 212056d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown 212156d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown /** 21229a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Set the current user-visible status for this route. 21239a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param status Status to display to the user to describe what the endpoint 21249a1de308cea2d160778fd977825f10a07b49d738Adam Powell * of this route is currently doing 21259a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 21269a1de308cea2d160778fd977825f10a07b49d738Adam Powell public void setStatus(CharSequence status) { 21279a1de308cea2d160778fd977825f10a07b49d738Adam Powell setStatusInt(status); 21289a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 2129ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell 2130ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell /** 2131ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * Set the RemoteControlClient responsible for reporting playback info for this 2132ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * user route. 2133ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * 2134ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * <p>If this route manages remote playback, the data exposed by this 2135ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * RemoteControlClient will be used to reflect and update information 2136ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * such as route volume info in related UIs.</p> 2137ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * 21381357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * <p>The RemoteControlClient must have been previously registered with 21391357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * {@link AudioManager#registerRemoteControlClient(RemoteControlClient)}.</p> 21401357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * 2141ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * @param rcc RemoteControlClient associated with this route 2142ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell */ 2143ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell public void setRemoteControlClient(RemoteControlClient rcc) { 2144ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell mRcc = rcc; 21451357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi updatePlaybackInfoOnRcc(); 2146ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell } 2147ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell 2148ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell /** 21494599696591f745b3a546197d2ba7e5cfc5562484Adam Powell * Retrieve the RemoteControlClient associated with this route, if one has been set. 21504599696591f745b3a546197d2ba7e5cfc5562484Adam Powell * 21514599696591f745b3a546197d2ba7e5cfc5562484Adam Powell * @return the RemoteControlClient associated with this route 21524599696591f745b3a546197d2ba7e5cfc5562484Adam Powell * @see #setRemoteControlClient(RemoteControlClient) 21534599696591f745b3a546197d2ba7e5cfc5562484Adam Powell */ 21544599696591f745b3a546197d2ba7e5cfc5562484Adam Powell public RemoteControlClient getRemoteControlClient() { 21554599696591f745b3a546197d2ba7e5cfc5562484Adam Powell return mRcc; 21564599696591f745b3a546197d2ba7e5cfc5562484Adam Powell } 21574599696591f745b3a546197d2ba7e5cfc5562484Adam Powell 21584599696591f745b3a546197d2ba7e5cfc5562484Adam Powell /** 2159ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * Set an icon that will be used to represent this route. 2160ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * The system may use this icon in picker UIs or similar. 2161ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * 2162ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * @param icon icon drawable to use to represent this route 2163ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell */ 2164ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell public void setIconDrawable(Drawable icon) { 2165ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell mIcon = icon; 2166ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell } 2167ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell 2168ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell /** 2169ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * Set an icon that will be used to represent this route. 2170ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * The system may use this icon in picker UIs or similar. 2171ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * 217271c69897ad0a55d590698bfa399bfe99c763b9dbAdam Powell * @param resId Resource ID of an icon drawable to use to represent this route 2173ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell */ 21747b9c912f536925ac6ec43935d6e97506851b33d6Tor Norbye public void setIconResource(@DrawableRes int resId) { 2175ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell setIconDrawable(sStatic.mResources.getDrawable(resId)); 2176ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell } 21771357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 21781357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 21791357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * Set a callback to be notified of volume update requests 21801357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @param vcb 21811357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 21821357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public void setVolumeCallback(VolumeCallback vcb) { 21831357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi mVcb = new VolumeCallbackInfo(vcb, this); 21841357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 21851357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 21861357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 21871357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * Defines whether playback associated with this route is "local" 21881357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * ({@link RouteInfo#PLAYBACK_TYPE_LOCAL}) or "remote" 21891357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * ({@link RouteInfo#PLAYBACK_TYPE_REMOTE}). 21901357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @param type 21911357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 21927c090d54e2c0eb5309d3f7dc131e137d9c986793Insun Kang public void setPlaybackType(@RouteInfo.PlaybackType int type) { 21931357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi if (mPlaybackType != type) { 21941357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi mPlaybackType = type; 2195430fc48865e5a371b08f180390946b96d73848feRoboErik configureSessionVolume(); 21961357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 21971357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 21981357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 21991357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 22001357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * Defines whether volume for the playback associated with this route is fixed 22011357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * ({@link RouteInfo#PLAYBACK_VOLUME_FIXED}) or can modified 22021357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * ({@link RouteInfo#PLAYBACK_VOLUME_VARIABLE}). 22031357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @param volumeHandling 22041357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 22057c090d54e2c0eb5309d3f7dc131e137d9c986793Insun Kang public void setVolumeHandling(@RouteInfo.PlaybackVolume int volumeHandling) { 22061357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi if (mVolumeHandling != volumeHandling) { 22071357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi mVolumeHandling = volumeHandling; 2208430fc48865e5a371b08f180390946b96d73848feRoboErik configureSessionVolume(); 22091357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 22101357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 22111357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 22121357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 22131357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * Defines at what volume the playback associated with this route is performed (for user 22141357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * feedback purposes). This information is only used when the playback is not local. 22151357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @param volume 22161357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 22171357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public void setVolume(int volume) { 22188e37a85bf3dc39519942698dc90a3951306b934bAdam Powell volume = Math.max(0, Math.min(volume, getVolumeMax())); 22191357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi if (mVolume != volume) { 22201357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi mVolume = volume; 2221430fc48865e5a371b08f180390946b96d73848feRoboErik if (mSvp != null) { 22220d0f67f5ee5f939a1b611bc4583212707afd9beeRoboErik mSvp.setCurrentVolume(mVolume); 22235d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik } 22248e37a85bf3dc39519942698dc90a3951306b934bAdam Powell dispatchRouteVolumeChanged(this); 2225f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell if (mGroup != null) { 2226f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell mGroup.memberVolumeChanged(this); 2227f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell } 22288e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 22298e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 22308e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 22318e37a85bf3dc39519942698dc90a3951306b934bAdam Powell @Override 22328e37a85bf3dc39519942698dc90a3951306b934bAdam Powell public void requestSetVolume(int volume) { 22338e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (mVolumeHandling == PLAYBACK_VOLUME_VARIABLE) { 22348e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (mVcb == null) { 22358e37a85bf3dc39519942698dc90a3951306b934bAdam Powell Log.e(TAG, "Cannot requestSetVolume on user route - no volume callback set"); 22368e37a85bf3dc39519942698dc90a3951306b934bAdam Powell return; 22378e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 22388e37a85bf3dc39519942698dc90a3951306b934bAdam Powell mVcb.vcb.onVolumeSetRequest(this, volume); 22398e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 22408e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 22418e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 22428e37a85bf3dc39519942698dc90a3951306b934bAdam Powell @Override 22438e37a85bf3dc39519942698dc90a3951306b934bAdam Powell public void requestUpdateVolume(int direction) { 22448e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (mVolumeHandling == PLAYBACK_VOLUME_VARIABLE) { 22458e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (mVcb == null) { 22468e37a85bf3dc39519942698dc90a3951306b934bAdam Powell Log.e(TAG, "Cannot requestChangeVolume on user route - no volumec callback set"); 22478e37a85bf3dc39519942698dc90a3951306b934bAdam Powell return; 22488e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 22498e37a85bf3dc39519942698dc90a3951306b934bAdam Powell mVcb.vcb.onVolumeUpdateRequest(this, direction); 22501357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 22511357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 22521357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 22531357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 22541357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * Defines the maximum volume at which the playback associated with this route is performed 22551357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * (for user feedback purposes). This information is only used when the playback is not 22561357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * local. 22571357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @param volumeMax 22581357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 22591357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public void setVolumeMax(int volumeMax) { 22601357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi if (mVolumeMax != volumeMax) { 22611357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi mVolumeMax = volumeMax; 2262430fc48865e5a371b08f180390946b96d73848feRoboErik configureSessionVolume(); 22631357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 22641357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 22651357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 22661357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 22671357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * Defines over what stream type the media is presented. 22681357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @param stream 22691357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 22701357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public void setPlaybackStream(int stream) { 22711357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi if (mPlaybackStream != stream) { 22721357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi mPlaybackStream = stream; 2273430fc48865e5a371b08f180390946b96d73848feRoboErik configureSessionVolume(); 22741357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 22751357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 22761357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 22771357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi private void updatePlaybackInfoOnRcc() { 2278430fc48865e5a371b08f180390946b96d73848feRoboErik configureSessionVolume(); 22795d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik } 22805d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik 22815d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik private void configureSessionVolume() { 22825d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik if (mRcc == null) { 22835d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik if (DEBUG) { 2284eadd6d2329972129c96dee390a8b786b37313d17Hyundo Moon Log.d(TAG, "No Rcc to configure volume for route " + getName()); 22855d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik } 22865d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik return; 22875d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik } 22885d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik MediaSession session = mRcc.getMediaSession(); 22895d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik if (session == null) { 22905d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik if (DEBUG) { 22915d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik Log.d(TAG, "Rcc has no session to configure volume"); 22925d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik } 22935d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik return; 22945d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik } 22955d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik if (mPlaybackType == RemoteControlClient.PLAYBACK_TYPE_REMOTE) { 22967c090d54e2c0eb5309d3f7dc131e137d9c986793Insun Kang @VolumeProvider.ControlType int volumeControl = 22977c090d54e2c0eb5309d3f7dc131e137d9c986793Insun Kang VolumeProvider.VOLUME_CONTROL_FIXED; 22985d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik switch (mVolumeHandling) { 22995d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik case RemoteControlClient.PLAYBACK_VOLUME_VARIABLE: 2300ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik volumeControl = VolumeProvider.VOLUME_CONTROL_ABSOLUTE; 23015d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik break; 23025d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik case RemoteControlClient.PLAYBACK_VOLUME_FIXED: 23035d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik default: 23045d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik break; 23051357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 23065d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik // Only register a new listener if necessary 23075d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik if (mSvp == null || mSvp.getVolumeControl() != volumeControl 23085d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik || mSvp.getMaxVolume() != mVolumeMax) { 23090d0f67f5ee5f939a1b611bc4583212707afd9beeRoboErik mSvp = new SessionVolumeProvider(volumeControl, mVolumeMax, mVolume); 23105d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik session.setPlaybackToRemote(mSvp); 23115d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik } 23125d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik } else { 23135d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik // We only know how to handle local and remote, fall back to local if not remote. 23149db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik AudioAttributes.Builder bob = new AudioAttributes.Builder(); 23159db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik bob.setLegacyStreamType(mPlaybackStream); 23169db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik session.setPlaybackToLocal(bob.build()); 23175d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik mSvp = null; 23181357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 23191357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 23201357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 2321ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik class SessionVolumeProvider extends VolumeProvider { 23225d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik 23237c090d54e2c0eb5309d3f7dc131e137d9c986793Insun Kang public SessionVolumeProvider(@VolumeProvider.ControlType int volumeControl, 23247c090d54e2c0eb5309d3f7dc131e137d9c986793Insun Kang int maxVolume, int currentVolume) { 23250d0f67f5ee5f939a1b611bc4583212707afd9beeRoboErik super(volumeControl, maxVolume, currentVolume); 23265d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik } 23275d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik 23285d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik @Override 23295d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik public void onSetVolumeTo(final int volume) { 23305d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik sStatic.mHandler.post(new Runnable() { 23315d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik @Override 23325d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik public void run() { 23335d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik if (mVcb != null) { 23345d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik mVcb.vcb.onVolumeSetRequest(mVcb.route, volume); 23355d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik } 23365d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik } 23375d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik }); 23385d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik } 23395d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik 23405d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik @Override 23411ff5b1648a051e9650614f0c0f1b3f449777db81RoboErik public void onAdjustVolume(final int direction) { 23425d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik sStatic.mHandler.post(new Runnable() { 23435d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik @Override 23445d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik public void run() { 23455d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik if (mVcb != null) { 23461ff5b1648a051e9650614f0c0f1b3f449777db81RoboErik mVcb.vcb.onVolumeUpdateRequest(mVcb.route, direction); 23475d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik } 23485d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik } 23495d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik }); 23505d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik } 23515d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik } 23529a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 23539a1de308cea2d160778fd977825f10a07b49d738Adam Powell 23549a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 23559a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Information about a route that consists of multiple other routes in a group. 23569a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 2357b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn public static class RouteGroup extends RouteInfo { 23589a1de308cea2d160778fd977825f10a07b49d738Adam Powell final ArrayList<RouteInfo> mRoutes = new ArrayList<RouteInfo>(); 23599a1de308cea2d160778fd977825f10a07b49d738Adam Powell private boolean mUpdateName; 23609a1de308cea2d160778fd977825f10a07b49d738Adam Powell 23619a1de308cea2d160778fd977825f10a07b49d738Adam Powell RouteGroup(RouteCategory category) { 23629a1de308cea2d160778fd977825f10a07b49d738Adam Powell super(category); 23639a1de308cea2d160778fd977825f10a07b49d738Adam Powell mGroup = this; 23648e37a85bf3dc39519942698dc90a3951306b934bAdam Powell mVolumeHandling = PLAYBACK_VOLUME_FIXED; 23659a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 23669a1de308cea2d160778fd977825f10a07b49d738Adam Powell 236769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown @Override 23680d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell CharSequence getName(Resources res) { 23699a1de308cea2d160778fd977825f10a07b49d738Adam Powell if (mUpdateName) updateName(); 23700d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell return super.getName(res); 23719a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 23729a1de308cea2d160778fd977825f10a07b49d738Adam Powell 23739a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 23749a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Add a route to this group. The route must not currently belong to another group. 23759a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 23769a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param route route to add to this group 23779a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 23789a1de308cea2d160778fd977825f10a07b49d738Adam Powell public void addRoute(RouteInfo route) { 23799a1de308cea2d160778fd977825f10a07b49d738Adam Powell if (route.getGroup() != null) { 23809a1de308cea2d160778fd977825f10a07b49d738Adam Powell throw new IllegalStateException("Route " + route + " is already part of a group."); 23819a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 23829a1de308cea2d160778fd977825f10a07b49d738Adam Powell if (route.getCategory() != mCategory) { 23839a1de308cea2d160778fd977825f10a07b49d738Adam Powell throw new IllegalArgumentException( 23849a1de308cea2d160778fd977825f10a07b49d738Adam Powell "Route cannot be added to a group with a different category. " + 23859a1de308cea2d160778fd977825f10a07b49d738Adam Powell "(Route category=" + route.getCategory() + 23869a1de308cea2d160778fd977825f10a07b49d738Adam Powell " group category=" + mCategory + ")"); 23879a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 2388d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell final int at = mRoutes.size(); 23899a1de308cea2d160778fd977825f10a07b49d738Adam Powell mRoutes.add(route); 2390d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell route.mGroup = this; 23919a1de308cea2d160778fd977825f10a07b49d738Adam Powell mUpdateName = true; 2392f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell updateVolume(); 23939a1de308cea2d160778fd977825f10a07b49d738Adam Powell routeUpdated(); 2394f3b653a21cdffe04c94c275e69ecb56e00766e82Adam Powell dispatchRouteGrouped(route, this, at); 23959a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 23969a1de308cea2d160778fd977825f10a07b49d738Adam Powell 23979a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 23989a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Add a route to this group before the specified index. 23999a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 24009a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param route route to add 24019a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param insertAt insert the new route before this index 24029a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 24039a1de308cea2d160778fd977825f10a07b49d738Adam Powell public void addRoute(RouteInfo route, int insertAt) { 24049a1de308cea2d160778fd977825f10a07b49d738Adam Powell if (route.getGroup() != null) { 24059a1de308cea2d160778fd977825f10a07b49d738Adam Powell throw new IllegalStateException("Route " + route + " is already part of a group."); 24069a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 24079a1de308cea2d160778fd977825f10a07b49d738Adam Powell if (route.getCategory() != mCategory) { 24089a1de308cea2d160778fd977825f10a07b49d738Adam Powell throw new IllegalArgumentException( 24099a1de308cea2d160778fd977825f10a07b49d738Adam Powell "Route cannot be added to a group with a different category. " + 24109a1de308cea2d160778fd977825f10a07b49d738Adam Powell "(Route category=" + route.getCategory() + 24119a1de308cea2d160778fd977825f10a07b49d738Adam Powell " group category=" + mCategory + ")"); 24129a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 24139a1de308cea2d160778fd977825f10a07b49d738Adam Powell mRoutes.add(insertAt, route); 2414d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell route.mGroup = this; 24159a1de308cea2d160778fd977825f10a07b49d738Adam Powell mUpdateName = true; 2416f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell updateVolume(); 24179a1de308cea2d160778fd977825f10a07b49d738Adam Powell routeUpdated(); 2418f3b653a21cdffe04c94c275e69ecb56e00766e82Adam Powell dispatchRouteGrouped(route, this, insertAt); 24199a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 24209a1de308cea2d160778fd977825f10a07b49d738Adam Powell 24219a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 24229a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Remove a route from this group. 24239a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 24249a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param route route to remove 24259a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 24269a1de308cea2d160778fd977825f10a07b49d738Adam Powell public void removeRoute(RouteInfo route) { 24279a1de308cea2d160778fd977825f10a07b49d738Adam Powell if (route.getGroup() != this) { 24289a1de308cea2d160778fd977825f10a07b49d738Adam Powell throw new IllegalArgumentException("Route " + route + 24299a1de308cea2d160778fd977825f10a07b49d738Adam Powell " is not a member of this group."); 24309a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 24319a1de308cea2d160778fd977825f10a07b49d738Adam Powell mRoutes.remove(route); 2432d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell route.mGroup = null; 24339a1de308cea2d160778fd977825f10a07b49d738Adam Powell mUpdateName = true; 2434f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell updateVolume(); 2435d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell dispatchRouteUngrouped(route, this); 24369a1de308cea2d160778fd977825f10a07b49d738Adam Powell routeUpdated(); 24379a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 24389a1de308cea2d160778fd977825f10a07b49d738Adam Powell 24399a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 24409a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Remove the route at the specified index from this group. 24419a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 24429a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param index index of the route to remove 24439a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 24449a1de308cea2d160778fd977825f10a07b49d738Adam Powell public void removeRoute(int index) { 2445d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell RouteInfo route = mRoutes.remove(index); 2446d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell route.mGroup = null; 24479a1de308cea2d160778fd977825f10a07b49d738Adam Powell mUpdateName = true; 2448f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell updateVolume(); 2449d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell dispatchRouteUngrouped(route, this); 24509a1de308cea2d160778fd977825f10a07b49d738Adam Powell routeUpdated(); 24519a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 24529a1de308cea2d160778fd977825f10a07b49d738Adam Powell 2453d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell /** 2454d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @return The number of routes in this group 2455d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell */ 2456d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell public int getRouteCount() { 2457d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell return mRoutes.size(); 2458d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell } 2459d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell 2460d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell /** 2461d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * Return the route in this group at the specified index 2462d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * 2463d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param index Index to fetch 2464d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @return The route at index 2465d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell */ 2466d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell public RouteInfo getRouteAt(int index) { 2467d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell return mRoutes.get(index); 2468d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell } 2469d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell 2470ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell /** 2471ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * Set an icon that will be used to represent this group. 2472ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * The system may use this icon in picker UIs or similar. 2473ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * 2474ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * @param icon icon drawable to use to represent this group 2475ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell */ 2476ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell public void setIconDrawable(Drawable icon) { 2477ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell mIcon = icon; 2478ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell } 2479ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell 2480ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell /** 2481ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * Set an icon that will be used to represent this group. 2482ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * The system may use this icon in picker UIs or similar. 2483ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * 248471c69897ad0a55d590698bfa399bfe99c763b9dbAdam Powell * @param resId Resource ID of an icon drawable to use to represent this group 2485ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell */ 24867b9c912f536925ac6ec43935d6e97506851b33d6Tor Norbye public void setIconResource(@DrawableRes int resId) { 2487ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell setIconDrawable(sStatic.mResources.getDrawable(resId)); 2488ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell } 2489ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell 24908e37a85bf3dc39519942698dc90a3951306b934bAdam Powell @Override 24918e37a85bf3dc39519942698dc90a3951306b934bAdam Powell public void requestSetVolume(int volume) { 24928e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final int maxVol = getVolumeMax(); 24938e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (maxVol == 0) { 24948e37a85bf3dc39519942698dc90a3951306b934bAdam Powell return; 24958e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 24968e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 24978e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final float scaledVolume = (float) volume / maxVol; 24988e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final int routeCount = getRouteCount(); 24998e37a85bf3dc39519942698dc90a3951306b934bAdam Powell for (int i = 0; i < routeCount; i++) { 25008e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final RouteInfo route = getRouteAt(i); 25018e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final int routeVol = (int) (scaledVolume * route.getVolumeMax()); 25028e37a85bf3dc39519942698dc90a3951306b934bAdam Powell route.requestSetVolume(routeVol); 25038e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 25048e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (volume != mVolume) { 25058e37a85bf3dc39519942698dc90a3951306b934bAdam Powell mVolume = volume; 25068e37a85bf3dc39519942698dc90a3951306b934bAdam Powell dispatchRouteVolumeChanged(this); 25078e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 25088e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 25098e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 25108e37a85bf3dc39519942698dc90a3951306b934bAdam Powell @Override 25118e37a85bf3dc39519942698dc90a3951306b934bAdam Powell public void requestUpdateVolume(int direction) { 25128e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final int maxVol = getVolumeMax(); 25138e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (maxVol == 0) { 25148e37a85bf3dc39519942698dc90a3951306b934bAdam Powell return; 25158e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 25168e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 25178e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final int routeCount = getRouteCount(); 2518f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell int volume = 0; 25198e37a85bf3dc39519942698dc90a3951306b934bAdam Powell for (int i = 0; i < routeCount; i++) { 25208e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final RouteInfo route = getRouteAt(i); 25218e37a85bf3dc39519942698dc90a3951306b934bAdam Powell route.requestUpdateVolume(direction); 2522f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell final int routeVol = route.getVolume(); 2523f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell if (routeVol > volume) { 2524f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell volume = routeVol; 2525f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell } 25268e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 25278e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (volume != mVolume) { 25288e37a85bf3dc39519942698dc90a3951306b934bAdam Powell mVolume = volume; 25298e37a85bf3dc39519942698dc90a3951306b934bAdam Powell dispatchRouteVolumeChanged(this); 25308e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 25318e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 25328e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 25339a1de308cea2d160778fd977825f10a07b49d738Adam Powell void memberNameChanged(RouteInfo info, CharSequence name) { 25349a1de308cea2d160778fd977825f10a07b49d738Adam Powell mUpdateName = true; 25359a1de308cea2d160778fd977825f10a07b49d738Adam Powell routeUpdated(); 25369a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 25379a1de308cea2d160778fd977825f10a07b49d738Adam Powell 25389a1de308cea2d160778fd977825f10a07b49d738Adam Powell void memberStatusChanged(RouteInfo info, CharSequence status) { 25399a1de308cea2d160778fd977825f10a07b49d738Adam Powell setStatusInt(status); 25409a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 25419a1de308cea2d160778fd977825f10a07b49d738Adam Powell 2542f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell void memberVolumeChanged(RouteInfo info) { 2543f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell updateVolume(); 2544f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell } 2545f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell 2546f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell void updateVolume() { 2547f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell // A group always represents the highest component volume value. 2548f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell final int routeCount = getRouteCount(); 2549f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell int volume = 0; 2550f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell for (int i = 0; i < routeCount; i++) { 2551f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell final int routeVol = getRouteAt(i).getVolume(); 2552f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell if (routeVol > volume) { 2553f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell volume = routeVol; 2554f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell } 2555f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell } 2556f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell if (volume != mVolume) { 2557f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell mVolume = volume; 2558f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell dispatchRouteVolumeChanged(this); 2559f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell } 2560f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell } 2561f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell 2562d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell @Override 2563d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell void routeUpdated() { 2564d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell int types = 0; 2565d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell final int count = mRoutes.size(); 2566b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell if (count == 0) { 2567b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell // Don't keep empty groups in the router. 256869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown MediaRouter.removeRouteStatic(this); 2569b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell return; 2570b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell } 2571b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell 25728e37a85bf3dc39519942698dc90a3951306b934bAdam Powell int maxVolume = 0; 25738e37a85bf3dc39519942698dc90a3951306b934bAdam Powell boolean isLocal = true; 25748e37a85bf3dc39519942698dc90a3951306b934bAdam Powell boolean isFixedVolume = true; 2575d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell for (int i = 0; i < count; i++) { 25768e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final RouteInfo route = mRoutes.get(i); 25778e37a85bf3dc39519942698dc90a3951306b934bAdam Powell types |= route.mSupportedTypes; 25788e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final int routeMaxVolume = route.getVolumeMax(); 25798e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (routeMaxVolume > maxVolume) { 25808e37a85bf3dc39519942698dc90a3951306b934bAdam Powell maxVolume = routeMaxVolume; 25818e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 25828e37a85bf3dc39519942698dc90a3951306b934bAdam Powell isLocal &= route.getPlaybackType() == PLAYBACK_TYPE_LOCAL; 25838e37a85bf3dc39519942698dc90a3951306b934bAdam Powell isFixedVolume &= route.getVolumeHandling() == PLAYBACK_VOLUME_FIXED; 2584d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell } 25858e37a85bf3dc39519942698dc90a3951306b934bAdam Powell mPlaybackType = isLocal ? PLAYBACK_TYPE_LOCAL : PLAYBACK_TYPE_REMOTE; 25868e37a85bf3dc39519942698dc90a3951306b934bAdam Powell mVolumeHandling = isFixedVolume ? PLAYBACK_VOLUME_FIXED : PLAYBACK_VOLUME_VARIABLE; 2587d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell mSupportedTypes = types; 25888e37a85bf3dc39519942698dc90a3951306b934bAdam Powell mVolumeMax = maxVolume; 2589d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell mIcon = count == 1 ? mRoutes.get(0).getIconDrawable() : null; 2590d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell super.routeUpdated(); 2591d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell } 2592d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell 25939a1de308cea2d160778fd977825f10a07b49d738Adam Powell void updateName() { 25949a1de308cea2d160778fd977825f10a07b49d738Adam Powell final StringBuilder sb = new StringBuilder(); 25959a1de308cea2d160778fd977825f10a07b49d738Adam Powell final int count = mRoutes.size(); 25969a1de308cea2d160778fd977825f10a07b49d738Adam Powell for (int i = 0; i < count; i++) { 25979a1de308cea2d160778fd977825f10a07b49d738Adam Powell final RouteInfo info = mRoutes.get(i); 2598b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell // TODO: There's probably a much more correct way to localize this. 2599eadd6d2329972129c96dee390a8b786b37313d17Hyundo Moon if (i > 0) { 2600eadd6d2329972129c96dee390a8b786b37313d17Hyundo Moon sb.append(", "); 2601eadd6d2329972129c96dee390a8b786b37313d17Hyundo Moon } 2602eadd6d2329972129c96dee390a8b786b37313d17Hyundo Moon sb.append(info.getName()); 26039a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 26049a1de308cea2d160778fd977825f10a07b49d738Adam Powell mName = sb.toString(); 26059a1de308cea2d160778fd977825f10a07b49d738Adam Powell mUpdateName = false; 26069a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 2607d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell 2608d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell @Override 2609d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell public String toString() { 2610d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell StringBuilder sb = new StringBuilder(super.toString()); 2611d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell sb.append('['); 2612d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell final int count = mRoutes.size(); 2613d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell for (int i = 0; i < count; i++) { 2614d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell if (i > 0) sb.append(", "); 2615d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell sb.append(mRoutes.get(i)); 2616d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell } 2617d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell sb.append(']'); 2618d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell return sb.toString(); 2619d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell } 26209a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 26219a1de308cea2d160778fd977825f10a07b49d738Adam Powell 26229a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 26239a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Definition of a category of routes. All routes belong to a category. 26249a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 2625b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn public static class RouteCategory { 26269a1de308cea2d160778fd977825f10a07b49d738Adam Powell CharSequence mName; 26270d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell int mNameResId; 26289a1de308cea2d160778fd977825f10a07b49d738Adam Powell int mTypes; 26299a1de308cea2d160778fd977825f10a07b49d738Adam Powell final boolean mGroupable; 2630705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell boolean mIsSystem; 26319a1de308cea2d160778fd977825f10a07b49d738Adam Powell 26329a1de308cea2d160778fd977825f10a07b49d738Adam Powell RouteCategory(CharSequence name, int types, boolean groupable) { 26339a1de308cea2d160778fd977825f10a07b49d738Adam Powell mName = name; 26349a1de308cea2d160778fd977825f10a07b49d738Adam Powell mTypes = types; 26359a1de308cea2d160778fd977825f10a07b49d738Adam Powell mGroupable = groupable; 26369a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 26379a1de308cea2d160778fd977825f10a07b49d738Adam Powell 26380d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell RouteCategory(int nameResId, int types, boolean groupable) { 26390d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell mNameResId = nameResId; 26400d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell mTypes = types; 26410d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell mGroupable = groupable; 26420d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell } 26430d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell 26449a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 26459a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @return the name of this route category 26469a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 26479a1de308cea2d160778fd977825f10a07b49d738Adam Powell public CharSequence getName() { 26480d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell return getName(sStatic.mResources); 26490d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell } 26505d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik 26510d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell /** 26520d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * Return the properly localized/configuration dependent name of this RouteCategory. 26535d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik * 26540d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * @param context Context to resolve name resources 26550d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * @return the name of this route category 26560d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell */ 26570d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public CharSequence getName(Context context) { 26580d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell return getName(context.getResources()); 26590d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell } 26605d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik 26610d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell CharSequence getName(Resources res) { 26620d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell if (mNameResId != 0) { 26630d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell return res.getText(mNameResId); 26640d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell } 26659a1de308cea2d160778fd977825f10a07b49d738Adam Powell return mName; 26669a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 26679a1de308cea2d160778fd977825f10a07b49d738Adam Powell 26689a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 2669d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * Return the current list of routes in this category that have been added 2670d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * to the MediaRouter. 26719a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 2672d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * <p>This list will not include routes that are nested within RouteGroups. 2673d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * A RouteGroup is treated as a single route within its category.</p> 2674d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * 2675d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param out a List to fill with the routes in this category. If this parameter is 2676d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * non-null, it will be cleared, filled with the current routes with this 2677d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * category, and returned. If this parameter is null, a new List will be 2678d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * allocated to report the category's current routes. 2679d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @return A list with the routes in this category that have been added to the MediaRouter. 26809a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 2681d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell public List<RouteInfo> getRoutes(List<RouteInfo> out) { 2682d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell if (out == null) { 2683d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell out = new ArrayList<RouteInfo>(); 2684d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell } else { 2685d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell out.clear(); 2686d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell } 2687d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell 2688b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn final int count = getRouteCountStatic(); 2689d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell for (int i = 0; i < count; i++) { 2690b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn final RouteInfo route = getRouteAtStatic(i); 2691d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell if (route.mCategory == this) { 2692d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell out.add(route); 2693d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell } 2694d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell } 2695d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell return out; 26969a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 26979a1de308cea2d160778fd977825f10a07b49d738Adam Powell 26989a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 26999a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @return Flag set describing the route types supported by this category 27009a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 27019a1de308cea2d160778fd977825f10a07b49d738Adam Powell public int getSupportedTypes() { 27029a1de308cea2d160778fd977825f10a07b49d738Adam Powell return mTypes; 27039a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 27049a1de308cea2d160778fd977825f10a07b49d738Adam Powell 27059a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 27069a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Return whether or not this category supports grouping. 27079a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 27089a1de308cea2d160778fd977825f10a07b49d738Adam Powell * <p>If this method returns true, all routes obtained from this category 2709d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * via calls to {@link #getRouteAt(int)} will be {@link MediaRouter.RouteGroup}s.</p> 27109a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 27119a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @return true if this category supports 27129a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 27139a1de308cea2d160778fd977825f10a07b49d738Adam Powell public boolean isGroupable() { 27149a1de308cea2d160778fd977825f10a07b49d738Adam Powell return mGroupable; 27159a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 27169a1de308cea2d160778fd977825f10a07b49d738Adam Powell 2717705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell /** 2718705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell * @return true if this is the category reserved for system routes. 2719705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell * @hide 2720705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell */ 2721705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell public boolean isSystem() { 2722705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell return mIsSystem; 2723705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 2724705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 272569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown @Override 27269a1de308cea2d160778fd977825f10a07b49d738Adam Powell public String toString() { 2727eadd6d2329972129c96dee390a8b786b37313d17Hyundo Moon return "RouteCategory{ name=" + getName() + " types=" + typesToString(mTypes) + 2728d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell " groupable=" + mGroupable + " }"; 27299a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 27309a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 27319a1de308cea2d160778fd977825f10a07b49d738Adam Powell 27329a1de308cea2d160778fd977825f10a07b49d738Adam Powell static class CallbackInfo { 27339a1de308cea2d160778fd977825f10a07b49d738Adam Powell public int type; 273466f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown public int flags; 2735b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn public final Callback cb; 2736b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn public final MediaRouter router; 27379a1de308cea2d160778fd977825f10a07b49d738Adam Powell 273866f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown public CallbackInfo(Callback cb, int type, int flags, MediaRouter router) { 27399a1de308cea2d160778fd977825f10a07b49d738Adam Powell this.cb = cb; 27409a1de308cea2d160778fd977825f10a07b49d738Adam Powell this.type = type; 274166f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown this.flags = flags; 2742b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn this.router = router; 27439a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 274466f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown 274566f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown public boolean filterRouteEvent(RouteInfo route) { 2746af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown return filterRouteEvent(route.mSupportedTypes); 2747af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown } 2748af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown 2749af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown public boolean filterRouteEvent(int supportedTypes) { 275066f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown return (flags & CALLBACK_FLAG_UNFILTERED_EVENTS) != 0 2751af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown || (type & supportedTypes) != 0; 275266f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown } 27539a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 27549a1de308cea2d160778fd977825f10a07b49d738Adam Powell 27559a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 27569a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Interface for receiving events about media routing changes. 27579a1de308cea2d160778fd977825f10a07b49d738Adam Powell * All methods of this interface will be called from the application's main thread. 275866f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * <p> 275966f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * A Callback will only receive events relevant to routes that the callback 276066f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * was registered for unless the {@link MediaRouter#CALLBACK_FLAG_UNFILTERED_EVENTS} 276166f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * flag was specified in {@link MediaRouter#addCallback(int, Callback, int)}. 276266f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * </p> 27639a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 276466f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * @see MediaRouter#addCallback(int, Callback, int) 27659a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @see MediaRouter#removeCallback(Callback) 27669a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 27670d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public static abstract class Callback { 27689a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 27699a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Called when the supplied route becomes selected as the active route 27709a1de308cea2d160778fd977825f10a07b49d738Adam Powell * for the given route type. 27719a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 2772d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param router the MediaRouter reporting the event 27739a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param type Type flag set indicating the routes that have been selected 27749a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param info Route that has been selected for the given route types 27759a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 27760d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public abstract void onRouteSelected(MediaRouter router, int type, RouteInfo info); 27779a1de308cea2d160778fd977825f10a07b49d738Adam Powell 27789a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 27799a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Called when the supplied route becomes unselected as the active route 27809a1de308cea2d160778fd977825f10a07b49d738Adam Powell * for the given route type. 27819a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 2782d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param router the MediaRouter reporting the event 27839a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param type Type flag set indicating the routes that have been unselected 27849a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param info Route that has been unselected for the given route types 27859a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 27860d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public abstract void onRouteUnselected(MediaRouter router, int type, RouteInfo info); 27879a1de308cea2d160778fd977825f10a07b49d738Adam Powell 27889a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 27899a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Called when a route for the specified type was added. 27909a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 2791d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param router the MediaRouter reporting the event 27929a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param info Route that has become available for use 27939a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 27940d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public abstract void onRouteAdded(MediaRouter router, RouteInfo info); 27959a1de308cea2d160778fd977825f10a07b49d738Adam Powell 27969a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 27979a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Called when a route for the specified type was removed. 27989a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 2799d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param router the MediaRouter reporting the event 28009a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param info Route that has been removed from availability 28019a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 28020d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public abstract void onRouteRemoved(MediaRouter router, RouteInfo info); 28039a1de308cea2d160778fd977825f10a07b49d738Adam Powell 28049a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 28059a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Called when an aspect of the indicated route has changed. 28069a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 28079a1de308cea2d160778fd977825f10a07b49d738Adam Powell * <p>This will not indicate that the types supported by this route have 28089a1de308cea2d160778fd977825f10a07b49d738Adam Powell * changed, only that cosmetic info such as name or status have been updated.</p> 28099a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 2810d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param router the MediaRouter reporting the event 28119a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param info The route that was changed 28129a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 28130d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public abstract void onRouteChanged(MediaRouter router, RouteInfo info); 2814d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell 2815d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell /** 2816d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * Called when a route is added to a group. 2817d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * 2818d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param router the MediaRouter reporting the event 2819d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param info The route that was added 2820d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param group The group the route was added to 2821d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param index The route index within group that info was added at 2822d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell */ 28230d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public abstract void onRouteGrouped(MediaRouter router, RouteInfo info, RouteGroup group, 28240d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell int index); 2825d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell 2826d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell /** 2827d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * Called when a route is removed from a group. 2828d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * 2829d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param router the MediaRouter reporting the event 2830d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param info The route that was removed 2831d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param group The group the route was removed from 2832d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell */ 28330d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public abstract void onRouteUngrouped(MediaRouter router, RouteInfo info, RouteGroup group); 28348e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 28358e37a85bf3dc39519942698dc90a3951306b934bAdam Powell /** 28368e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * Called when a route's volume changes. 28378e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * 28388e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * @param router the MediaRouter reporting the event 28398e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * @param info The route with altered volume 28408e37a85bf3dc39519942698dc90a3951306b934bAdam Powell */ 28418e37a85bf3dc39519942698dc90a3951306b934bAdam Powell public abstract void onRouteVolumeChanged(MediaRouter router, RouteInfo info); 284292130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown 284392130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown /** 284492130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * Called when a route's presentation display changes. 284592130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * <p> 284692130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * This method is called whenever the route's presentation display becomes 284792130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * available, is removes or has changes to some of its properties (such as its size). 284892130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * </p> 284992130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * 285092130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * @param router the MediaRouter reporting the event 285192130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * @param info The route whose presentation display changed 285292130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * 285392130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * @see RouteInfo#getPresentationDisplay() 285492130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown */ 285592130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown public void onRoutePresentationDisplayChanged(MediaRouter router, RouteInfo info) { 285692130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown } 28579a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 28589a1de308cea2d160778fd977825f10a07b49d738Adam Powell 28599a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 28600d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * Stub implementation of {@link MediaRouter.Callback}. 28610d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * Each abstract method is defined as a no-op. Override just the ones 28629a1de308cea2d160778fd977825f10a07b49d738Adam Powell * you need. 28639a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 28640d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public static class SimpleCallback extends Callback { 28659a1de308cea2d160778fd977825f10a07b49d738Adam Powell 28669a1de308cea2d160778fd977825f10a07b49d738Adam Powell @Override 2867d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell public void onRouteSelected(MediaRouter router, int type, RouteInfo info) { 28689a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 28699a1de308cea2d160778fd977825f10a07b49d738Adam Powell 28709a1de308cea2d160778fd977825f10a07b49d738Adam Powell @Override 2871d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell public void onRouteUnselected(MediaRouter router, int type, RouteInfo info) { 28729a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 28739a1de308cea2d160778fd977825f10a07b49d738Adam Powell 28749a1de308cea2d160778fd977825f10a07b49d738Adam Powell @Override 2875d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell public void onRouteAdded(MediaRouter router, RouteInfo info) { 28769a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 28779a1de308cea2d160778fd977825f10a07b49d738Adam Powell 28789a1de308cea2d160778fd977825f10a07b49d738Adam Powell @Override 2879d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell public void onRouteRemoved(MediaRouter router, RouteInfo info) { 28809a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 28819a1de308cea2d160778fd977825f10a07b49d738Adam Powell 28829a1de308cea2d160778fd977825f10a07b49d738Adam Powell @Override 2883d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell public void onRouteChanged(MediaRouter router, RouteInfo info) { 28849a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 28859a1de308cea2d160778fd977825f10a07b49d738Adam Powell 28869a1de308cea2d160778fd977825f10a07b49d738Adam Powell @Override 2887d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell public void onRouteGrouped(MediaRouter router, RouteInfo info, RouteGroup group, 2888d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell int index) { 28899a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 28909a1de308cea2d160778fd977825f10a07b49d738Adam Powell 28919a1de308cea2d160778fd977825f10a07b49d738Adam Powell @Override 2892d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell public void onRouteUngrouped(MediaRouter router, RouteInfo info, RouteGroup group) { 28939a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 2894d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell 28958e37a85bf3dc39519942698dc90a3951306b934bAdam Powell @Override 28968e37a85bf3dc39519942698dc90a3951306b934bAdam Powell public void onRouteVolumeChanged(MediaRouter router, RouteInfo info) { 28978e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 28989a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 28991357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 29001357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi static class VolumeCallbackInfo { 29011357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public final VolumeCallback vcb; 29021357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public final RouteInfo route; 29031357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 29041357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public VolumeCallbackInfo(VolumeCallback vcb, RouteInfo route) { 29051357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi this.vcb = vcb; 29061357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi this.route = route; 29071357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 29081357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 29091357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 29101357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 29111357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * Interface for receiving events about volume changes. 29121357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * All methods of this interface will be called from the application's main thread. 29131357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * 29141357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * <p>A VolumeCallback will only receive events relevant to routes that the callback 29151357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * was registered for.</p> 29161357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * 29171357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @see UserRouteInfo#setVolumeCallback(VolumeCallback) 29181357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 29191357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public static abstract class VolumeCallback { 29201357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 29211357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * Called when the volume for the route should be increased or decreased. 29221357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @param info the route affected by this event 29231357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @param direction an integer indicating whether the volume is to be increased 29241357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * (positive value) or decreased (negative value). 29251357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * For bundled changes, the absolute value indicates the number of changes 29261357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * in the same direction, e.g. +3 corresponds to three "volume up" changes. 29271357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 29281357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public abstract void onVolumeUpdateRequest(RouteInfo info, int direction); 29291357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 29301357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * Called when the volume for the route should be set to the given value 29311357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @param info the route affected by this event 29321357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @param volume an integer indicating the new volume value that should be used, always 29331357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * between 0 and the value set by {@link UserRouteInfo#setVolumeMax(int)}. 29341357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 29351357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public abstract void onVolumeSetRequest(RouteInfo info, int volume); 29361357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 29371357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 29388e37a85bf3dc39519942698dc90a3951306b934bAdam Powell static class VolumeChangeReceiver extends BroadcastReceiver { 29398e37a85bf3dc39519942698dc90a3951306b934bAdam Powell @Override 29408e37a85bf3dc39519942698dc90a3951306b934bAdam Powell public void onReceive(Context context, Intent intent) { 29418e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (intent.getAction().equals(AudioManager.VOLUME_CHANGED_ACTION)) { 29428e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final int streamType = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, 29438e37a85bf3dc39519942698dc90a3951306b934bAdam Powell -1); 29448e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (streamType != AudioManager.STREAM_MUSIC) { 29458e37a85bf3dc39519942698dc90a3951306b934bAdam Powell return; 29468e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 29478e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 29488e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final int newVolume = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, 0); 29498e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final int oldVolume = intent.getIntExtra( 29508e37a85bf3dc39519942698dc90a3951306b934bAdam Powell AudioManager.EXTRA_PREV_VOLUME_STREAM_VALUE, 0); 29518e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (newVolume != oldVolume) { 29528e37a85bf3dc39519942698dc90a3951306b934bAdam Powell systemVolumeChanged(newVolume); 29538e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 29548e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 29558e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 2956705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 29578e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 2958705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell static class WifiDisplayStatusChangedReceiver extends BroadcastReceiver { 2959705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell @Override 2960705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell public void onReceive(Context context, Intent intent) { 2961705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell if (intent.getAction().equals(DisplayManager.ACTION_WIFI_DISPLAY_STATUS_CHANGED)) { 2962705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell updateWifiDisplayStatus((WifiDisplayStatus) intent.getParcelableExtra( 2963705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell DisplayManager.EXTRA_WIFI_DISPLAY_STATUS)); 2964705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 2965705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 29668e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 29679a1de308cea2d160778fd977825f10a07b49d738Adam Powell} 2968