MediaRouter.java revision f8e38e2dbbf3410179c9e18e05b7d4022720cfb6
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; 23d86b8fea43ebb6e5c31691b44d8ceb0d8d3c9072Jeff Sharkeyimport android.annotation.SystemService; 24ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackbornimport android.app.ActivityThread; 258e37a85bf3dc39519942698dc90a3951306b934bAdam Powellimport android.content.BroadcastReceiver; 269a1de308cea2d160778fd977825f10a07b49d738Adam Powellimport android.content.Context; 278e37a85bf3dc39519942698dc90a3951306b934bAdam Powellimport android.content.Intent; 288e37a85bf3dc39519942698dc90a3951306b934bAdam Powellimport android.content.IntentFilter; 29af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brownimport android.content.pm.PackageManager; 30b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackbornimport android.content.res.Resources; 31ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powellimport android.graphics.drawable.Drawable; 32705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powellimport android.hardware.display.DisplayManager; 33705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powellimport android.hardware.display.WifiDisplay; 34705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powellimport android.hardware.display.WifiDisplayStatus; 355d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErikimport android.media.session.MediaSession; 369a1de308cea2d160778fd977825f10a07b49d738Adam Powellimport android.os.Handler; 37632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackbornimport android.os.IBinder; 38af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brownimport android.os.Process; 39632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackbornimport android.os.RemoteException; 40632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackbornimport android.os.ServiceManager; 4169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brownimport android.os.UserHandle; 42632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackbornimport android.text.TextUtils; 439a1de308cea2d160778fd977825f10a07b49d738Adam Powellimport android.util.Log; 44705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powellimport android.view.Display; 459a1de308cea2d160778fd977825f10a07b49d738Adam Powell 469dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kangimport java.lang.annotation.Retention; 479dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kangimport java.lang.annotation.RetentionPolicy; 489a1de308cea2d160778fd977825f10a07b49d738Adam Powellimport java.util.ArrayList; 499a1de308cea2d160778fd977825f10a07b49d738Adam Powellimport java.util.HashMap; 50d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powellimport java.util.List; 51e6585b32ea586743258a5457e2184ffc087f2d2fKenny Rootimport java.util.Objects; 5239d5c6172503620ac3761148adac5fd7fa20d02dAdam Powellimport java.util.concurrent.CopyOnWriteArrayList; 539a1de308cea2d160778fd977825f10a07b49d738Adam Powell 549a1de308cea2d160778fd977825f10a07b49d738Adam Powell/** 559a1de308cea2d160778fd977825f10a07b49d738Adam Powell * MediaRouter allows applications to control the routing of media channels 569a1de308cea2d160778fd977825f10a07b49d738Adam Powell * and streams from the current device to external speakers and destination devices. 579a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 58b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn * <p>A MediaRouter is retrieved through {@link Context#getSystemService(String) 59b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn * Context.getSystemService()} of a {@link Context#MEDIA_ROUTER_SERVICE 60b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn * Context.MEDIA_ROUTER_SERVICE}. 61b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn * 62b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn * <p>The media router API is not thread-safe; all interactions with it must be 63b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn * done from the main thread of the process.</p> 649a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 65d86b8fea43ebb6e5c31691b44d8ceb0d8d3c9072Jeff Sharkey@SystemService(Context.MEDIA_ROUTER_SERVICE) 669a1de308cea2d160778fd977825f10a07b49d738Adam Powellpublic class MediaRouter { 679a1de308cea2d160778fd977825f10a07b49d738Adam Powell private static final String TAG = "MediaRouter"; 6869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); 699a1de308cea2d160778fd977825f10a07b49d738Adam Powell 7092130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown static class Static implements DisplayManager.DisplayListener { 71eadd6d2329972129c96dee390a8b786b37313d17Hyundo Moon final String mPackageName; 72b35c445f34e1a18e17aef3e3dfbc1c39b4d1815cAdam Powell final Resources mResources; 73632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn final IAudioService mAudioService; 74705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell final DisplayManager mDisplayService; 7569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final IMediaRouterService mMediaRouterService; 76b35c445f34e1a18e17aef3e3dfbc1c39b4d1815cAdam Powell final Handler mHandler; 7739d5c6172503620ac3761148adac5fd7fa20d02dAdam Powell final CopyOnWriteArrayList<CallbackInfo> mCallbacks = 7839d5c6172503620ac3761148adac5fd7fa20d02dAdam Powell new CopyOnWriteArrayList<CallbackInfo>(); 79b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn 80b35c445f34e1a18e17aef3e3dfbc1c39b4d1815cAdam Powell final ArrayList<RouteInfo> mRoutes = new ArrayList<RouteInfo>(); 81b35c445f34e1a18e17aef3e3dfbc1c39b4d1815cAdam Powell final ArrayList<RouteCategory> mCategories = new ArrayList<RouteCategory>(); 82b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn 83b35c445f34e1a18e17aef3e3dfbc1c39b4d1815cAdam Powell final RouteCategory mSystemCategory; 84632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn 85705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell final AudioRoutesInfo mCurAudioRoutesInfo = new AudioRoutesInfo(); 86b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn 87705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell RouteInfo mDefaultAudioVideo; 88b35c445f34e1a18e17aef3e3dfbc1c39b4d1815cAdam Powell RouteInfo mBluetoothA2dpRoute; 89b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn 90b35c445f34e1a18e17aef3e3dfbc1c39b4d1815cAdam Powell RouteInfo mSelectedRoute; 919a1de308cea2d160778fd977825f10a07b49d738Adam Powell 92af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown final boolean mCanConfigureWifiDisplays; 9366f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown boolean mActivelyScanningWifiDisplays; 94ce468a35b388ca46578934706b38dbae94941643Jeff Brown String mPreviousActiveWifiDisplayAddress; 95705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 9669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown int mDiscoveryRequestRouteTypes; 9769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown boolean mDiscoverRequestActiveScan; 9869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 9969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown int mCurrentUserId = -1; 10069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown IMediaRouterClient mClient; 10169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown MediaRouterClientState mClientState; 10269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 103705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell final IAudioRoutesObserver.Stub mAudioRoutesObserver = new IAudioRoutesObserver.Stub() { 10466f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown @Override 105632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn public void dispatchAudioRoutesChanged(final AudioRoutesInfo newRoutes) { 106632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn mHandler.post(new Runnable() { 107632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn @Override public void run() { 108705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell updateAudioRoutes(newRoutes); 109632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } 110632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn }); 111632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } 112632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn }; 113632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn 114b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn Static(Context appContext) { 115eadd6d2329972129c96dee390a8b786b37313d17Hyundo Moon mPackageName = appContext.getPackageName(); 116eadd6d2329972129c96dee390a8b786b37313d17Hyundo Moon mResources = appContext.getResources(); 117b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn mHandler = new Handler(appContext.getMainLooper()); 1189a1de308cea2d160778fd977825f10a07b49d738Adam Powell 119632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn IBinder b = ServiceManager.getService(Context.AUDIO_SERVICE); 120632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn mAudioService = IAudioService.Stub.asInterface(b); 1219a1de308cea2d160778fd977825f10a07b49d738Adam Powell 122705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell mDisplayService = (DisplayManager) appContext.getSystemService(Context.DISPLAY_SERVICE); 123705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 12469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mMediaRouterService = IMediaRouterService.Stub.asInterface( 12569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown ServiceManager.getService(Context.MEDIA_ROUTER_SERVICE)); 12669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 127dd0a19266d5c837069da1ea188744d54c8d723a8Adam Powell mSystemCategory = new RouteCategory( 128dd0a19266d5c837069da1ea188744d54c8d723a8Adam Powell com.android.internal.R.string.default_audio_route_category_name, 129705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell ROUTE_TYPE_LIVE_AUDIO | ROUTE_TYPE_LIVE_VIDEO, false); 130705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell mSystemCategory.mIsSystem = true; 131af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown 132af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown // Only the system can configure wifi displays. The display manager 133af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown // enforces this with a permission check. Set a flag here so that we 134af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown // know whether this process is actually allowed to scan and connect. 135af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown mCanConfigureWifiDisplays = appContext.checkPermission( 136af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown Manifest.permission.CONFIGURE_WIFI_DISPLAY, 137af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown Process.myPid(), Process.myUid()) == PackageManager.PERMISSION_GRANTED; 138b35c445f34e1a18e17aef3e3dfbc1c39b4d1815cAdam Powell } 139b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn 140b35c445f34e1a18e17aef3e3dfbc1c39b4d1815cAdam Powell // Called after sStatic is initialized 1418e37a85bf3dc39519942698dc90a3951306b934bAdam Powell void startMonitoringRoutes(Context appContext) { 142705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell mDefaultAudioVideo = new RouteInfo(mSystemCategory); 143705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell mDefaultAudioVideo.mNameResId = com.android.internal.R.string.default_audio_route_name; 144705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell mDefaultAudioVideo.mSupportedTypes = ROUTE_TYPE_LIVE_AUDIO | ROUTE_TYPE_LIVE_VIDEO; 1455830b0b33618940d65197cec99d697b21908fec8Chong Zhang mDefaultAudioVideo.updatePresentationDisplay(); 146bd6118ffb453c7597c8679bc6bfefb4887d7662fSungsoo if (((AudioManager) appContext.getSystemService(Context.AUDIO_SERVICE)) 147bd6118ffb453c7597c8679bc6bfefb4887d7662fSungsoo .isVolumeFixed()) { 148bd6118ffb453c7597c8679bc6bfefb4887d7662fSungsoo mDefaultAudioVideo.mVolumeHandling = RouteInfo.PLAYBACK_VOLUME_FIXED; 149bd6118ffb453c7597c8679bc6bfefb4887d7662fSungsoo } 150bd6118ffb453c7597c8679bc6bfefb4887d7662fSungsoo 1512ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell addRouteStatic(mDefaultAudioVideo); 152632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn 1532ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell // This will select the active wifi display route if there is one. 1542ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell updateWifiDisplayStatus(mDisplayService.getWifiDisplayStatus()); 1552ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell 1562ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell appContext.registerReceiver(new WifiDisplayStatusChangedReceiver(), 1572ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell new IntentFilter(DisplayManager.ACTION_WIFI_DISPLAY_STATUS_CHANGED)); 1588e37a85bf3dc39519942698dc90a3951306b934bAdam Powell appContext.registerReceiver(new VolumeChangeReceiver(), 1598e37a85bf3dc39519942698dc90a3951306b934bAdam Powell new IntentFilter(AudioManager.VOLUME_CHANGED_ACTION)); 1608e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 16192130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown mDisplayService.registerDisplayListener(this, mHandler); 16292130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown 163705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell AudioRoutesInfo newAudioRoutes = null; 164632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn try { 165705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell newAudioRoutes = mAudioService.startWatchingRoutes(mAudioRoutesObserver); 166632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } catch (RemoteException e) { 167632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } 168705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell if (newAudioRoutes != null) { 1692ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell // This will select the active BT route if there is one and the current 1702ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell // selected route is the default system route, or if there is no selected 1712ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell // route yet. 172705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell updateAudioRoutes(newAudioRoutes); 173632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } 174705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 17569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Bind to the media router service. 17669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown rebindAsUser(UserHandle.myUserId()); 17769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 1782ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell // Select the default route if the above didn't sync us up 1792ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell // appropriately with relevant system state. 1802ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell if (mSelectedRoute == null) { 18169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown selectDefaultRouteStatic(); 1822ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell } 183632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } 184632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn 185705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell void updateAudioRoutes(AudioRoutesInfo newRoutes) { 18676512a3d80dff2d32b68f3b3b6a14d4ed81ae90aSungsoo Lim boolean audioRoutesChanged = false; 1876156017c2217d0fbbbb03434986250ec6bbd69d8John Spurlock if (newRoutes.mainType != mCurAudioRoutesInfo.mainType) { 1886156017c2217d0fbbbb03434986250ec6bbd69d8John Spurlock mCurAudioRoutesInfo.mainType = newRoutes.mainType; 189632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn int name; 1906156017c2217d0fbbbb03434986250ec6bbd69d8John Spurlock if ((newRoutes.mainType&AudioRoutesInfo.MAIN_HEADPHONES) != 0 1916156017c2217d0fbbbb03434986250ec6bbd69d8John Spurlock || (newRoutes.mainType&AudioRoutesInfo.MAIN_HEADSET) != 0) { 192632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn name = com.android.internal.R.string.default_audio_route_name_headphones; 1936156017c2217d0fbbbb03434986250ec6bbd69d8John Spurlock } else if ((newRoutes.mainType&AudioRoutesInfo.MAIN_DOCK_SPEAKERS) != 0) { 194632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn name = com.android.internal.R.string.default_audio_route_name_dock_speakers; 1956156017c2217d0fbbbb03434986250ec6bbd69d8John Spurlock } else if ((newRoutes.mainType&AudioRoutesInfo.MAIN_HDMI) != 0) { 1964131a37366d59b5e61f55c4e48d2b22ee0c4cad4Adam Powell name = com.android.internal.R.string.default_media_route_name_hdmi; 197632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } else { 198632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn name = com.android.internal.R.string.default_audio_route_name; 199632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } 200b3658569e9a87afe1b3168837cc282235fd4d1f8Sungsoo mDefaultAudioVideo.mNameResId = name; 201b3658569e9a87afe1b3168837cc282235fd4d1f8Sungsoo dispatchRouteChanged(mDefaultAudioVideo); 20276512a3d80dff2d32b68f3b3b6a14d4ed81ae90aSungsoo Lim audioRoutesChanged = true; 203632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } 204bcf21e913af7252fb1994e07b6cf179321ecd049Adam Powell 2056156017c2217d0fbbbb03434986250ec6bbd69d8John Spurlock if (!TextUtils.equals(newRoutes.bluetoothName, mCurAudioRoutesInfo.bluetoothName)) { 2066156017c2217d0fbbbb03434986250ec6bbd69d8John Spurlock mCurAudioRoutesInfo.bluetoothName = newRoutes.bluetoothName; 2076156017c2217d0fbbbb03434986250ec6bbd69d8John Spurlock if (mCurAudioRoutesInfo.bluetoothName != null) { 208b3658569e9a87afe1b3168837cc282235fd4d1f8Sungsoo if (mBluetoothA2dpRoute == null) { 209b3658569e9a87afe1b3168837cc282235fd4d1f8Sungsoo // BT connected 210b3658569e9a87afe1b3168837cc282235fd4d1f8Sungsoo final RouteInfo info = new RouteInfo(mSystemCategory); 2116156017c2217d0fbbbb03434986250ec6bbd69d8John Spurlock info.mName = mCurAudioRoutesInfo.bluetoothName; 212b3658569e9a87afe1b3168837cc282235fd4d1f8Sungsoo info.mDescription = mResources.getText( 21356d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown com.android.internal.R.string.bluetooth_a2dp_audio_route_name); 214632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn info.mSupportedTypes = ROUTE_TYPE_LIVE_AUDIO; 2159dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang info.mDeviceType = RouteInfo.DEVICE_TYPE_BLUETOOTH; 216b3658569e9a87afe1b3168837cc282235fd4d1f8Sungsoo mBluetoothA2dpRoute = info; 217b3658569e9a87afe1b3168837cc282235fd4d1f8Sungsoo addRouteStatic(mBluetoothA2dpRoute); 218632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } else { 219b3658569e9a87afe1b3168837cc282235fd4d1f8Sungsoo mBluetoothA2dpRoute.mName = mCurAudioRoutesInfo.bluetoothName; 220b3658569e9a87afe1b3168837cc282235fd4d1f8Sungsoo dispatchRouteChanged(mBluetoothA2dpRoute); 221632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } 222b3658569e9a87afe1b3168837cc282235fd4d1f8Sungsoo } else if (mBluetoothA2dpRoute != null) { 223b3658569e9a87afe1b3168837cc282235fd4d1f8Sungsoo // BT disconnected 224b3658569e9a87afe1b3168837cc282235fd4d1f8Sungsoo removeRouteStatic(mBluetoothA2dpRoute); 225b3658569e9a87afe1b3168837cc282235fd4d1f8Sungsoo mBluetoothA2dpRoute = null; 226bcf21e913af7252fb1994e07b6cf179321ecd049Adam Powell } 22776512a3d80dff2d32b68f3b3b6a14d4ed81ae90aSungsoo Lim audioRoutesChanged = true; 228bcf21e913af7252fb1994e07b6cf179321ecd049Adam Powell } 22976512a3d80dff2d32b68f3b3b6a14d4ed81ae90aSungsoo Lim 23076512a3d80dff2d32b68f3b3b6a14d4ed81ae90aSungsoo Lim if (audioRoutesChanged) { 231742e379863ff08a880cb6d9e5f274da7589f9a53Jaewan Kim Log.v(TAG, "Audio routes updated: " + newRoutes + ", a2dp=" + isBluetoothA2dpOn()); 232f8e38e2dbbf3410179c9e18e05b7d4022720cfb6Sungsoo Lim if (mSelectedRoute == null || mSelectedRoute == mDefaultAudioVideo 233f8e38e2dbbf3410179c9e18e05b7d4022720cfb6Sungsoo Lim || mSelectedRoute == mBluetoothA2dpRoute) { 234f8e38e2dbbf3410179c9e18e05b7d4022720cfb6Sungsoo Lim selectRouteStatic(ROUTE_TYPE_LIVE_AUDIO, getDefaultSystemAudioRoute(), false); 235f8e38e2dbbf3410179c9e18e05b7d4022720cfb6Sungsoo Lim } 236742e379863ff08a880cb6d9e5f274da7589f9a53Jaewan Kim } 237b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn } 23892130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown 23976512a3d80dff2d32b68f3b3b6a14d4ed81ae90aSungsoo Lim RouteInfo getDefaultSystemAudioRoute() { 24076512a3d80dff2d32b68f3b3b6a14d4ed81ae90aSungsoo Lim boolean globalBluetoothA2doOn = false; 24176512a3d80dff2d32b68f3b3b6a14d4ed81ae90aSungsoo Lim try { 24276512a3d80dff2d32b68f3b3b6a14d4ed81ae90aSungsoo Lim globalBluetoothA2doOn = mMediaRouterService.isGlobalBluetoothA2doOn(); 24376512a3d80dff2d32b68f3b3b6a14d4ed81ae90aSungsoo Lim } catch (RemoteException ex) { 24476512a3d80dff2d32b68f3b3b6a14d4ed81ae90aSungsoo Lim Log.e(TAG, "Unable to call isSystemBluetoothA2doOn.", ex); 24576512a3d80dff2d32b68f3b3b6a14d4ed81ae90aSungsoo Lim } 24676512a3d80dff2d32b68f3b3b6a14d4ed81ae90aSungsoo Lim return (globalBluetoothA2doOn && mBluetoothA2dpRoute != null) 24776512a3d80dff2d32b68f3b3b6a14d4ed81ae90aSungsoo Lim ? mBluetoothA2dpRoute : mDefaultAudioVideo; 24876512a3d80dff2d32b68f3b3b6a14d4ed81ae90aSungsoo Lim } 24976512a3d80dff2d32b68f3b3b6a14d4ed81ae90aSungsoo Lim 25076512a3d80dff2d32b68f3b3b6a14d4ed81ae90aSungsoo Lim RouteInfo getCurrentSystemAudioRoute() { 25176512a3d80dff2d32b68f3b3b6a14d4ed81ae90aSungsoo Lim return (isBluetoothA2dpOn() && mBluetoothA2dpRoute != null) 25276512a3d80dff2d32b68f3b3b6a14d4ed81ae90aSungsoo Lim ? mBluetoothA2dpRoute : mDefaultAudioVideo; 25376512a3d80dff2d32b68f3b3b6a14d4ed81ae90aSungsoo Lim } 25476512a3d80dff2d32b68f3b3b6a14d4ed81ae90aSungsoo Lim 255fa6f70e225a7370c1ecb21ee7076c9086ecb9e9aSungsoo boolean isBluetoothA2dpOn() { 256fa6f70e225a7370c1ecb21ee7076c9086ecb9e9aSungsoo try { 257fa6f70e225a7370c1ecb21ee7076c9086ecb9e9aSungsoo return mAudioService.isBluetoothA2dpOn(); 258fa6f70e225a7370c1ecb21ee7076c9086ecb9e9aSungsoo } catch (RemoteException e) { 259fa6f70e225a7370c1ecb21ee7076c9086ecb9e9aSungsoo Log.e(TAG, "Error querying Bluetooth A2DP state", e); 260fa6f70e225a7370c1ecb21ee7076c9086ecb9e9aSungsoo return false; 261fa6f70e225a7370c1ecb21ee7076c9086ecb9e9aSungsoo } 262fa6f70e225a7370c1ecb21ee7076c9086ecb9e9aSungsoo } 263fa6f70e225a7370c1ecb21ee7076c9086ecb9e9aSungsoo 26469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown void updateDiscoveryRequest() { 26569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // What are we looking for today? 26669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown int routeTypes = 0; 26769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown int passiveRouteTypes = 0; 26869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown boolean activeScan = false; 26969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown boolean activeScanWifiDisplay = false; 27069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final int count = mCallbacks.size(); 27169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown for (int i = 0; i < count; i++) { 27269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown CallbackInfo cbi = mCallbacks.get(i); 27369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if ((cbi.flags & (CALLBACK_FLAG_PERFORM_ACTIVE_SCAN 27469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown | CALLBACK_FLAG_REQUEST_DISCOVERY)) != 0) { 27569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Discovery explicitly requested. 27669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown routeTypes |= cbi.type; 27769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } else if ((cbi.flags & CALLBACK_FLAG_PASSIVE_DISCOVERY) != 0) { 27869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Discovery only passively requested. 27969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown passiveRouteTypes |= cbi.type; 28069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } else { 28169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Legacy case since applications don't specify the discovery flag. 28269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Unfortunately we just have to assume they always need discovery 28369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // whenever they have a callback registered. 28469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown routeTypes |= cbi.type; 28569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 28669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if ((cbi.flags & CALLBACK_FLAG_PERFORM_ACTIVE_SCAN) != 0) { 28769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown activeScan = true; 288af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown if ((cbi.type & ROUTE_TYPE_REMOTE_DISPLAY) != 0) { 28969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown activeScanWifiDisplay = true; 29069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 29169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 29269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 29369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (routeTypes != 0 || activeScan) { 29469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // If someone else requests discovery then enable the passive listeners. 29569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // This is used by the MediaRouteButton and MediaRouteActionProvider since 29669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // they don't receive lifecycle callbacks from the Activity. 29769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown routeTypes |= passiveRouteTypes; 29869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 29969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 30069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Update wifi display scanning. 301ce468a35b388ca46578934706b38dbae94941643Jeff Brown // TODO: All of this should be managed by the media router service. 302ce468a35b388ca46578934706b38dbae94941643Jeff Brown if (mCanConfigureWifiDisplays) { 303ce468a35b388ca46578934706b38dbae94941643Jeff Brown if (mSelectedRoute != null 304ce468a35b388ca46578934706b38dbae94941643Jeff Brown && mSelectedRoute.matchesTypes(ROUTE_TYPE_REMOTE_DISPLAY)) { 305ce468a35b388ca46578934706b38dbae94941643Jeff Brown // Don't scan while already connected to a remote display since 306ce468a35b388ca46578934706b38dbae94941643Jeff Brown // it may interfere with the ongoing transmission. 307ce468a35b388ca46578934706b38dbae94941643Jeff Brown activeScanWifiDisplay = false; 30866f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown } 309ce468a35b388ca46578934706b38dbae94941643Jeff Brown if (activeScanWifiDisplay) { 310ce468a35b388ca46578934706b38dbae94941643Jeff Brown if (!mActivelyScanningWifiDisplays) { 311ce468a35b388ca46578934706b38dbae94941643Jeff Brown mActivelyScanningWifiDisplays = true; 312ce468a35b388ca46578934706b38dbae94941643Jeff Brown mDisplayService.startWifiDisplayScan(); 313ce468a35b388ca46578934706b38dbae94941643Jeff Brown } 314ce468a35b388ca46578934706b38dbae94941643Jeff Brown } else { 315ce468a35b388ca46578934706b38dbae94941643Jeff Brown if (mActivelyScanningWifiDisplays) { 316ce468a35b388ca46578934706b38dbae94941643Jeff Brown mActivelyScanningWifiDisplays = false; 317ce468a35b388ca46578934706b38dbae94941643Jeff Brown mDisplayService.stopWifiDisplayScan(); 318ce468a35b388ca46578934706b38dbae94941643Jeff Brown } 31966f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown } 32066f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown } 32166f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown 32269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Tell the media router service all about it. 32369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (routeTypes != mDiscoveryRequestRouteTypes 32469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown || activeScan != mDiscoverRequestActiveScan) { 32569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mDiscoveryRequestRouteTypes = routeTypes; 32669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mDiscoverRequestActiveScan = activeScan; 32769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown publishClientDiscoveryRequest(); 32866f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown } 32966f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown } 33066f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown 33192130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown @Override 33292130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown public void onDisplayAdded(int displayId) { 33392130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown updatePresentationDisplays(displayId); 33492130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown } 33592130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown 33692130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown @Override 33792130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown public void onDisplayChanged(int displayId) { 33892130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown updatePresentationDisplays(displayId); 33992130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown } 34092130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown 34192130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown @Override 34292130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown public void onDisplayRemoved(int displayId) { 34392130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown updatePresentationDisplays(displayId); 34492130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown } 34592130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown 34692130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown public Display[] getAllPresentationDisplays() { 34792130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown return mDisplayService.getDisplays(DisplayManager.DISPLAY_CATEGORY_PRESENTATION); 34892130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown } 34992130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown 35092130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown private void updatePresentationDisplays(int changedDisplayId) { 35192130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown final int count = mRoutes.size(); 35292130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown for (int i = 0; i < count; i++) { 3535830b0b33618940d65197cec99d697b21908fec8Chong Zhang final RouteInfo route = mRoutes.get(i); 3545830b0b33618940d65197cec99d697b21908fec8Chong Zhang if (route.updatePresentationDisplay() || (route.mPresentationDisplay != null 3555830b0b33618940d65197cec99d697b21908fec8Chong Zhang && route.mPresentationDisplay.getDisplayId() == changedDisplayId)) { 3565830b0b33618940d65197cec99d697b21908fec8Chong Zhang dispatchRoutePresentationDisplayChanged(route); 35792130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown } 35892130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown } 35992130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown } 36069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 36169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown void setSelectedRoute(RouteInfo info, boolean explicit) { 36269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Must be non-reentrant. 36369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mSelectedRoute = info; 36469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown publishClientSelectedRoute(explicit); 36569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 36669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 36769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown void rebindAsUser(int userId) { 36869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (mCurrentUserId != userId || userId < 0 || mClient == null) { 36969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (mClient != null) { 37069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown try { 37169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mMediaRouterService.unregisterClient(mClient); 37269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } catch (RemoteException ex) { 37369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Log.e(TAG, "Unable to unregister media router client.", ex); 37469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 37569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mClient = null; 37669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 37769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 37869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mCurrentUserId = userId; 37969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 38069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown try { 38169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Client client = new Client(); 382eadd6d2329972129c96dee390a8b786b37313d17Hyundo Moon mMediaRouterService.registerClientAsUser(client, mPackageName, userId); 38369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mClient = client; 38469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } catch (RemoteException ex) { 38569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Log.e(TAG, "Unable to register media router client.", ex); 38669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 38769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 38869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown publishClientDiscoveryRequest(); 38969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown publishClientSelectedRoute(false); 39069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown updateClientState(); 39169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 39269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 39369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 39469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown void publishClientDiscoveryRequest() { 39569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (mClient != null) { 39669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown try { 39769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mMediaRouterService.setDiscoveryRequest(mClient, 39869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mDiscoveryRequestRouteTypes, mDiscoverRequestActiveScan); 39969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } catch (RemoteException ex) { 40069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Log.e(TAG, "Unable to publish media router client discovery request.", ex); 40169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 40269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 40369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 40469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 40569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown void publishClientSelectedRoute(boolean explicit) { 40669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (mClient != null) { 40769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown try { 40869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mMediaRouterService.setSelectedRoute(mClient, 40969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mSelectedRoute != null ? mSelectedRoute.mGlobalRouteId : null, 41069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown explicit); 41169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } catch (RemoteException ex) { 41269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Log.e(TAG, "Unable to publish media router client selected route.", ex); 41369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 41469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 41569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 41669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 41769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown void updateClientState() { 41869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Update the client state. 41969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mClientState = null; 42069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (mClient != null) { 42169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown try { 42269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mClientState = mMediaRouterService.getState(mClient); 42369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } catch (RemoteException ex) { 42469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Log.e(TAG, "Unable to retrieve media router client state.", ex); 42569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 42669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 42769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final ArrayList<MediaRouterClientState.RouteInfo> globalRoutes = 42869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mClientState != null ? mClientState.routes : null; 42969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 43069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Add or update routes. 43169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final int globalRouteCount = globalRoutes != null ? globalRoutes.size() : 0; 43269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown for (int i = 0; i < globalRouteCount; i++) { 43369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final MediaRouterClientState.RouteInfo globalRoute = globalRoutes.get(i); 43469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown RouteInfo route = findGlobalRoute(globalRoute.id); 43569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (route == null) { 43669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route = makeGlobalRoute(globalRoute); 43769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown addRouteStatic(route); 43869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } else { 43969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown updateGlobalRoute(route, globalRoute); 44069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 44169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 44269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 44369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Remove defunct routes. 44469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown outer: for (int i = mRoutes.size(); i-- > 0; ) { 44569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final RouteInfo route = mRoutes.get(i); 44669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final String globalRouteId = route.mGlobalRouteId; 44769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (globalRouteId != null) { 44869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown for (int j = 0; j < globalRouteCount; j++) { 44969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown MediaRouterClientState.RouteInfo globalRoute = globalRoutes.get(j); 45069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (globalRouteId.equals(globalRoute.id)) { 45169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown continue outer; // found 45269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 45369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 45469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // not found 45569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown removeRouteStatic(route); 45669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 45769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 45869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 45969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 46069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown void requestSetVolume(RouteInfo route, int volume) { 46169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (route.mGlobalRouteId != null && mClient != null) { 46269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown try { 46369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mMediaRouterService.requestSetVolume(mClient, 46469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mGlobalRouteId, volume); 46569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } catch (RemoteException ex) { 46669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Log.w(TAG, "Unable to request volume change.", ex); 46769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 46869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 46969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 47069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 47169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown void requestUpdateVolume(RouteInfo route, int direction) { 47269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (route.mGlobalRouteId != null && mClient != null) { 47369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown try { 47469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mMediaRouterService.requestUpdateVolume(mClient, 47569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mGlobalRouteId, direction); 47669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } catch (RemoteException ex) { 47769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Log.w(TAG, "Unable to request volume change.", ex); 47869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 47969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 48069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 48169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 48269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown RouteInfo makeGlobalRoute(MediaRouterClientState.RouteInfo globalRoute) { 483b3658569e9a87afe1b3168837cc282235fd4d1f8Sungsoo RouteInfo route = new RouteInfo(mSystemCategory); 48469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mGlobalRouteId = globalRoute.id; 48569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mName = globalRoute.name; 48669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mDescription = globalRoute.description; 48769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mSupportedTypes = globalRoute.supportedTypes; 4889dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang route.mDeviceType = globalRoute.deviceType; 48969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mEnabled = globalRoute.enabled; 49039ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown route.setRealStatusCode(globalRoute.statusCode); 49169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mPlaybackType = globalRoute.playbackType; 49269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mPlaybackStream = globalRoute.playbackStream; 49369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mVolume = globalRoute.volume; 49469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mVolumeMax = globalRoute.volumeMax; 49569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mVolumeHandling = globalRoute.volumeHandling; 4965830b0b33618940d65197cec99d697b21908fec8Chong Zhang route.mPresentationDisplayId = globalRoute.presentationDisplayId; 4975830b0b33618940d65197cec99d697b21908fec8Chong Zhang route.updatePresentationDisplay(); 49869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return route; 49969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 50069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 50169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown void updateGlobalRoute(RouteInfo route, MediaRouterClientState.RouteInfo globalRoute) { 50269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown boolean changed = false; 50369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown boolean volumeChanged = false; 50469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown boolean presentationDisplayChanged = false; 50569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 506e6585b32ea586743258a5457e2184ffc087f2d2fKenny Root if (!Objects.equals(route.mName, globalRoute.name)) { 50769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mName = globalRoute.name; 50869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown changed = true; 50969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 510e6585b32ea586743258a5457e2184ffc087f2d2fKenny Root if (!Objects.equals(route.mDescription, globalRoute.description)) { 51169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mDescription = globalRoute.description; 51269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown changed = true; 51369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 514af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown final int oldSupportedTypes = route.mSupportedTypes; 515af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown if (oldSupportedTypes != globalRoute.supportedTypes) { 51669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mSupportedTypes = globalRoute.supportedTypes; 51769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown changed = true; 51869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 51969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (route.mEnabled != globalRoute.enabled) { 52069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mEnabled = globalRoute.enabled; 52169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown changed = true; 52269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 52339ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown if (route.mRealStatusCode != globalRoute.statusCode) { 52439ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown route.setRealStatusCode(globalRoute.statusCode); 52569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown changed = true; 52669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 52769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (route.mPlaybackType != globalRoute.playbackType) { 52869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mPlaybackType = globalRoute.playbackType; 52969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown changed = true; 53069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 53169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (route.mPlaybackStream != globalRoute.playbackStream) { 53269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mPlaybackStream = globalRoute.playbackStream; 53369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown changed = true; 53469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 53569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (route.mVolume != globalRoute.volume) { 53669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mVolume = globalRoute.volume; 53769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown changed = true; 53869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown volumeChanged = true; 53969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 54069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (route.mVolumeMax != globalRoute.volumeMax) { 54169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mVolumeMax = globalRoute.volumeMax; 54269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown changed = true; 54369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown volumeChanged = true; 54469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 54569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (route.mVolumeHandling != globalRoute.volumeHandling) { 54669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mVolumeHandling = globalRoute.volumeHandling; 54769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown changed = true; 54869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown volumeChanged = true; 54969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 5505830b0b33618940d65197cec99d697b21908fec8Chong Zhang if (route.mPresentationDisplayId != globalRoute.presentationDisplayId) { 5515830b0b33618940d65197cec99d697b21908fec8Chong Zhang route.mPresentationDisplayId = globalRoute.presentationDisplayId; 5525830b0b33618940d65197cec99d697b21908fec8Chong Zhang route.updatePresentationDisplay(); 55369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown changed = true; 55469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown presentationDisplayChanged = true; 55569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 55669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 55769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (changed) { 558af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown dispatchRouteChanged(route, oldSupportedTypes); 55969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 56069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (volumeChanged) { 56169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown dispatchRouteVolumeChanged(route); 56269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 56369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (presentationDisplayChanged) { 56469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown dispatchRoutePresentationDisplayChanged(route); 56569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 56669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 56769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 56869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown RouteInfo findGlobalRoute(String globalRouteId) { 56969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final int count = mRoutes.size(); 57069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown for (int i = 0; i < count; i++) { 57169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final RouteInfo route = mRoutes.get(i); 57269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (globalRouteId.equals(route.mGlobalRouteId)) { 57369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return route; 57469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 57569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 57669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return null; 57769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 57869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 579b3658569e9a87afe1b3168837cc282235fd4d1f8Sungsoo boolean isPlaybackActive() { 580b3658569e9a87afe1b3168837cc282235fd4d1f8Sungsoo if (mClient != null) { 581b3658569e9a87afe1b3168837cc282235fd4d1f8Sungsoo try { 582b3658569e9a87afe1b3168837cc282235fd4d1f8Sungsoo return mMediaRouterService.isPlaybackActive(mClient); 583b3658569e9a87afe1b3168837cc282235fd4d1f8Sungsoo } catch (RemoteException ex) { 584b3658569e9a87afe1b3168837cc282235fd4d1f8Sungsoo Log.e(TAG, "Unable to retrieve playback active state.", ex); 585b3658569e9a87afe1b3168837cc282235fd4d1f8Sungsoo } 586b3658569e9a87afe1b3168837cc282235fd4d1f8Sungsoo } 587b3658569e9a87afe1b3168837cc282235fd4d1f8Sungsoo return false; 588b3658569e9a87afe1b3168837cc282235fd4d1f8Sungsoo } 589b3658569e9a87afe1b3168837cc282235fd4d1f8Sungsoo 59069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final class Client extends IMediaRouterClient.Stub { 59169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown @Override 59269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public void onStateChanged() { 59369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mHandler.post(new Runnable() { 59469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown @Override 59569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public void run() { 59669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (Client.this == mClient) { 59769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown updateClientState(); 59869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 59969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 60069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown }); 60169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 602b3658569e9a87afe1b3168837cc282235fd4d1f8Sungsoo 603b3658569e9a87afe1b3168837cc282235fd4d1f8Sungsoo @Override 604b3658569e9a87afe1b3168837cc282235fd4d1f8Sungsoo public void onRestoreRoute() { 60576512a3d80dff2d32b68f3b3b6a14d4ed81ae90aSungsoo Lim // Skip restoring route if the selected route is not a system audio route, or 60676512a3d80dff2d32b68f3b3b6a14d4ed81ae90aSungsoo Lim // MediaRouter is initializing. 607b3658569e9a87afe1b3168837cc282235fd4d1f8Sungsoo if ((mSelectedRoute != mDefaultAudioVideo && mSelectedRoute != mBluetoothA2dpRoute) 60876512a3d80dff2d32b68f3b3b6a14d4ed81ae90aSungsoo Lim || mSelectedRoute == null) { 609b3658569e9a87afe1b3168837cc282235fd4d1f8Sungsoo return; 610b3658569e9a87afe1b3168837cc282235fd4d1f8Sungsoo } 61176512a3d80dff2d32b68f3b3b6a14d4ed81ae90aSungsoo Lim mSelectedRoute.select(); 612b3658569e9a87afe1b3168837cc282235fd4d1f8Sungsoo } 61369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 614b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn } 6159a1de308cea2d160778fd977825f10a07b49d738Adam Powell 616b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn static Static sStatic; 6179a1de308cea2d160778fd977825f10a07b49d738Adam Powell 6189a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 6199a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Route type flag for live audio. 6209a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 6219a1de308cea2d160778fd977825f10a07b49d738Adam Powell * <p>A device that supports live audio routing will allow the media audio stream 6229a1de308cea2d160778fd977825f10a07b49d738Adam Powell * to be routed to supported destinations. This can include internal speakers or 6239a1de308cea2d160778fd977825f10a07b49d738Adam Powell * audio jacks on the device itself, A2DP devices, and more.</p> 6249a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 6259a1de308cea2d160778fd977825f10a07b49d738Adam Powell * <p>Once initiated this routing is transparent to the application. All audio 6269a1de308cea2d160778fd977825f10a07b49d738Adam Powell * played on the media stream will be routed to the selected destination.</p> 6279a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 62869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public static final int ROUTE_TYPE_LIVE_AUDIO = 1 << 0; 6299a1de308cea2d160778fd977825f10a07b49d738Adam Powell 6309a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 631705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell * Route type flag for live video. 632705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell * 633705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell * <p>A device that supports live video routing will allow a mirrored version 634705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell * of the device's primary display or a customized 635705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell * {@link android.app.Presentation Presentation} to be routed to supported destinations.</p> 636705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell * 637705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell * <p>Once initiated, display mirroring is transparent to the application. 638705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell * While remote routing is active the application may use a 639705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell * {@link android.app.Presentation Presentation} to replace the mirrored view 640705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell * on the external display with different content.</p> 64192130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * 64292130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * @see RouteInfo#getPresentationDisplay() 64392130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * @see android.app.Presentation 644705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell */ 64569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public static final int ROUTE_TYPE_LIVE_VIDEO = 1 << 1; 64669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 64769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown /** 64869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * Temporary interop constant to identify remote displays. 64969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * @hide To be removed when media router API is updated. 65069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown */ 65169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public static final int ROUTE_TYPE_REMOTE_DISPLAY = 1 << 2; 652705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 653705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell /** 6549a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Route type flag for application-specific usage. 6559a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 6569a1de308cea2d160778fd977825f10a07b49d738Adam Powell * <p>Unlike other media route types, user routes are managed by the application. 6579a1de308cea2d160778fd977825f10a07b49d738Adam Powell * The MediaRouter will manage and dispatch events for user routes, but the application 6589a1de308cea2d160778fd977825f10a07b49d738Adam Powell * is expected to interpret the meaning of these events and perform the requested 6599a1de308cea2d160778fd977825f10a07b49d738Adam Powell * routing tasks.</p> 6609a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 66169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public static final int ROUTE_TYPE_USER = 1 << 23; 66269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 66369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown static final int ROUTE_TYPE_ANY = ROUTE_TYPE_LIVE_AUDIO | ROUTE_TYPE_LIVE_VIDEO 66469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown | ROUTE_TYPE_REMOTE_DISPLAY | ROUTE_TYPE_USER; 6659a1de308cea2d160778fd977825f10a07b49d738Adam Powell 66666f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown /** 66766f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * Flag for {@link #addCallback}: Actively scan for routes while this callback 66866f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * is registered. 66966f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * <p> 67066f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * When this flag is specified, the media router will actively scan for new 67166f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * routes. Certain routes, such as wifi display routes, may not be discoverable 67266f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * except when actively scanning. This flag is typically used when the route picker 67366f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * dialog has been opened by the user to ensure that the route information is 67466f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * up to date. 67566f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * </p><p> 67666f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * Active scanning may consume a significant amount of power and may have intrusive 67766f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * effects on wireless connectivity. Therefore it is important that active scanning 67866f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * only be requested when it is actually needed to satisfy a user request to 67966f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * discover and select a new route. 68066f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * </p> 68166f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown */ 68214507e257af5d71577574e25cbd690c4b54c9272Jeff Brown public static final int CALLBACK_FLAG_PERFORM_ACTIVE_SCAN = 1 << 0; 68366f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown 68466f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown /** 68566f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * Flag for {@link #addCallback}: Do not filter route events. 68666f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * <p> 68766f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * When this flag is specified, the callback will be invoked for event that affect any 68869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * route even if they do not match the callback's filter. 68966f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * </p> 69066f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown */ 69166f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown public static final int CALLBACK_FLAG_UNFILTERED_EVENTS = 1 << 1; 69266f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown 69369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown /** 69469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * Explicitly requests discovery. 69569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * 69669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * @hide Future API ported from support library. Revisit this later. 69769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown */ 69869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public static final int CALLBACK_FLAG_REQUEST_DISCOVERY = 1 << 2; 69969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 70069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown /** 70169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * Requests that discovery be performed but only if there is some other active 70269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * callback already registered. 70369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * 70469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * @hide Compatibility workaround for the fact that applications do not currently 70569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * request discovery explicitly (except when using the support library API). 70669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown */ 70769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public static final int CALLBACK_FLAG_PASSIVE_DISCOVERY = 1 << 3; 70869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 7090abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown /** 7100abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * Flag for {@link #isRouteAvailable}: Ignore the default route. 7110abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * <p> 7120abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * This flag is used to determine whether a matching non-default route is available. 7130abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * This constraint may be used to decide whether to offer the route chooser dialog 7140abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * to the user. There is no point offering the chooser if there are no 7150abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * non-default choices. 7160abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * </p> 7170abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * 7180abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * @hide Future API ported from support library. Revisit this later. 7190abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown */ 7200abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown public static final int AVAILABILITY_FLAG_IGNORE_DEFAULT_ROUTE = 1 << 0; 7210abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown 7229a1de308cea2d160778fd977825f10a07b49d738Adam Powell // Maps application contexts 7239a1de308cea2d160778fd977825f10a07b49d738Adam Powell static final HashMap<Context, MediaRouter> sRouters = new HashMap<Context, MediaRouter>(); 7249a1de308cea2d160778fd977825f10a07b49d738Adam Powell 7259a1de308cea2d160778fd977825f10a07b49d738Adam Powell static String typesToString(int types) { 7269a1de308cea2d160778fd977825f10a07b49d738Adam Powell final StringBuilder result = new StringBuilder(); 7279a1de308cea2d160778fd977825f10a07b49d738Adam Powell if ((types & ROUTE_TYPE_LIVE_AUDIO) != 0) { 7289a1de308cea2d160778fd977825f10a07b49d738Adam Powell result.append("ROUTE_TYPE_LIVE_AUDIO "); 7299a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 7302bb7c122ef6ce8539dfbaeb3292adcd942185f82Bryan Mawhinney if ((types & ROUTE_TYPE_LIVE_VIDEO) != 0) { 7312bb7c122ef6ce8539dfbaeb3292adcd942185f82Bryan Mawhinney result.append("ROUTE_TYPE_LIVE_VIDEO "); 7322bb7c122ef6ce8539dfbaeb3292adcd942185f82Bryan Mawhinney } 73369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if ((types & ROUTE_TYPE_REMOTE_DISPLAY) != 0) { 73469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown result.append("ROUTE_TYPE_REMOTE_DISPLAY "); 73569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 7369a1de308cea2d160778fd977825f10a07b49d738Adam Powell if ((types & ROUTE_TYPE_USER) != 0) { 7379a1de308cea2d160778fd977825f10a07b49d738Adam Powell result.append("ROUTE_TYPE_USER "); 7389a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 7399a1de308cea2d160778fd977825f10a07b49d738Adam Powell return result.toString(); 7409a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 7419a1de308cea2d160778fd977825f10a07b49d738Adam Powell 742b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn /** @hide */ 743b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn public MediaRouter(Context context) { 744b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn synchronized (Static.class) { 745b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn if (sStatic == null) { 7468e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final Context appContext = context.getApplicationContext(); 7478e37a85bf3dc39519942698dc90a3951306b934bAdam Powell sStatic = new Static(appContext); 7488e37a85bf3dc39519942698dc90a3951306b934bAdam Powell sStatic.startMonitoringRoutes(appContext); 749b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn } 7509a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 7519a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 7529a1de308cea2d160778fd977825f10a07b49d738Adam Powell 753690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell /** 7543afc18af2cea898753b10e8575dcf20c11356bcaJeff Brown * Gets the default route for playing media content on the system. 7553afc18af2cea898753b10e8575dcf20c11356bcaJeff Brown * <p> 7563afc18af2cea898753b10e8575dcf20c11356bcaJeff Brown * The system always provides a default route. 7573afc18af2cea898753b10e8575dcf20c11356bcaJeff Brown * </p> 7583afc18af2cea898753b10e8575dcf20c11356bcaJeff Brown * 7593afc18af2cea898753b10e8575dcf20c11356bcaJeff Brown * @return The default route, which is guaranteed to never be null. 760690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell */ 7613afc18af2cea898753b10e8575dcf20c11356bcaJeff Brown public RouteInfo getDefaultRoute() { 762705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell return sStatic.mDefaultAudioVideo; 763690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell } 764690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell 765690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell /** 76659579ce59d6e2c42e6ea1b389ba7e228aaa9122fSungsoo Lim * Returns a Bluetooth route if available, otherwise the default route. 76759579ce59d6e2c42e6ea1b389ba7e228aaa9122fSungsoo Lim * @hide 76859579ce59d6e2c42e6ea1b389ba7e228aaa9122fSungsoo Lim */ 76959579ce59d6e2c42e6ea1b389ba7e228aaa9122fSungsoo Lim public RouteInfo getFallbackRoute() { 77059579ce59d6e2c42e6ea1b389ba7e228aaa9122fSungsoo Lim return (sStatic.mBluetoothA2dpRoute != null) 77159579ce59d6e2c42e6ea1b389ba7e228aaa9122fSungsoo Lim ? sStatic.mBluetoothA2dpRoute : sStatic.mDefaultAudioVideo; 77259579ce59d6e2c42e6ea1b389ba7e228aaa9122fSungsoo Lim } 77359579ce59d6e2c42e6ea1b389ba7e228aaa9122fSungsoo Lim 77459579ce59d6e2c42e6ea1b389ba7e228aaa9122fSungsoo Lim /** 7754599696591f745b3a546197d2ba7e5cfc5562484Adam Powell * @hide for use by framework routing UI 7764599696591f745b3a546197d2ba7e5cfc5562484Adam Powell */ 7773afc18af2cea898753b10e8575dcf20c11356bcaJeff Brown public RouteCategory getSystemCategory() { 7784599696591f745b3a546197d2ba7e5cfc5562484Adam Powell return sStatic.mSystemCategory; 7794599696591f745b3a546197d2ba7e5cfc5562484Adam Powell } 7804599696591f745b3a546197d2ba7e5cfc5562484Adam Powell 7810abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown /** @hide */ 7820abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown public RouteInfo getSelectedRoute() { 7830abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown return getSelectedRoute(ROUTE_TYPE_ANY); 7840abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown } 7850abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown 7864599696591f745b3a546197d2ba7e5cfc5562484Adam Powell /** 7871cf2ca83584a4cf0aa3ded787bd191b9a60e3521Adam Powell * Return the currently selected route for any of the given types 788690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell * 789690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell * @param type route types 790690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell * @return the selected route 791690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell */ 792690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell public RouteInfo getSelectedRoute(int type) { 7931cf2ca83584a4cf0aa3ded787bd191b9a60e3521Adam Powell if (sStatic.mSelectedRoute != null && 7941cf2ca83584a4cf0aa3ded787bd191b9a60e3521Adam Powell (sStatic.mSelectedRoute.mSupportedTypes & type) != 0) { 7951cf2ca83584a4cf0aa3ded787bd191b9a60e3521Adam Powell // If the selected route supports any of the types supplied, it's still considered 7961cf2ca83584a4cf0aa3ded787bd191b9a60e3521Adam Powell // 'selected' for that type. 7971cf2ca83584a4cf0aa3ded787bd191b9a60e3521Adam Powell return sStatic.mSelectedRoute; 7981cf2ca83584a4cf0aa3ded787bd191b9a60e3521Adam Powell } else if (type == ROUTE_TYPE_USER) { 7991cf2ca83584a4cf0aa3ded787bd191b9a60e3521Adam Powell // The caller specifically asked for a user route and the currently selected route 8001cf2ca83584a4cf0aa3ded787bd191b9a60e3521Adam Powell // doesn't qualify. 8011cf2ca83584a4cf0aa3ded787bd191b9a60e3521Adam Powell return null; 8021cf2ca83584a4cf0aa3ded787bd191b9a60e3521Adam Powell } 8031cf2ca83584a4cf0aa3ded787bd191b9a60e3521Adam Powell // If the above didn't match and we're not specifically asking for a user route, 8041cf2ca83584a4cf0aa3ded787bd191b9a60e3521Adam Powell // consider the default selected. 8051cf2ca83584a4cf0aa3ded787bd191b9a60e3521Adam Powell return sStatic.mDefaultAudioVideo; 806690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell } 807690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell 8089a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 8090abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * Returns true if there is a route that matches the specified types. 8100abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * <p> 8110abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * This method returns true if there are any available routes that match the types 8120abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * regardless of whether they are enabled or disabled. If the 8130abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * {@link #AVAILABILITY_FLAG_IGNORE_DEFAULT_ROUTE} flag is specified, then 8140abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * the method will only consider non-default routes. 8150abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * </p> 8160abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * 8170abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * @param types The types to match. 8180abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * @param flags Flags to control the determination of whether a route may be available. 8190abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * May be zero or {@link #AVAILABILITY_FLAG_IGNORE_DEFAULT_ROUTE}. 8200abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * @return True if a matching route may be available. 8210abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * 8220abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * @hide Future API ported from support library. Revisit this later. 8230abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown */ 8240abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown public boolean isRouteAvailable(int types, int flags) { 8250abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown final int count = sStatic.mRoutes.size(); 8260abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown for (int i = 0; i < count; i++) { 8270abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown RouteInfo route = sStatic.mRoutes.get(i); 8280abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown if (route.matchesTypes(types)) { 8290abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown if ((flags & AVAILABILITY_FLAG_IGNORE_DEFAULT_ROUTE) == 0 8300abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown || route != sStatic.mDefaultAudioVideo) { 8310abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown return true; 8320abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown } 8330abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown } 8340abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown } 8350abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown 8360abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown // It doesn't look like we can find a matching route right now. 8370abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown return false; 8380abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown } 8390abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown 8400abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown /** 8419a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Add a callback to listen to events about specific kinds of media routes. 8429a1de308cea2d160778fd977825f10a07b49d738Adam Powell * If the specified callback is already registered, its registration will be updated for any 8439a1de308cea2d160778fd977825f10a07b49d738Adam Powell * additional route types specified. 84466f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * <p> 84566f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * This is a convenience method that has the same effect as calling 84666f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * {@link #addCallback(int, Callback, int)} without flags. 84766f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * </p> 8489a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 8499a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param types Types of routes this callback is interested in 8509a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param cb Callback to add 8519a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 8529a1de308cea2d160778fd977825f10a07b49d738Adam Powell public void addCallback(int types, Callback cb) { 85366f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown addCallback(types, cb, 0); 85466f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown } 85566f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown 85666f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown /** 85766f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * Add a callback to listen to events about specific kinds of media routes. 85866f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * If the specified callback is already registered, its registration will be updated for any 85966f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * additional route types specified. 86066f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * <p> 86166f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * By default, the callback will only be invoked for events that affect routes 86266f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * that match the specified selector. The filtering may be disabled by specifying 86366f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * the {@link #CALLBACK_FLAG_UNFILTERED_EVENTS} flag. 86466f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * </p> 86566f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * 86666f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * @param types Types of routes this callback is interested in 86766f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * @param cb Callback to add 86866f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * @param flags Flags to control the behavior of the callback. 86914507e257af5d71577574e25cbd690c4b54c9272Jeff Brown * May be zero or a combination of {@link #CALLBACK_FLAG_PERFORM_ACTIVE_SCAN} and 87066f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * {@link #CALLBACK_FLAG_UNFILTERED_EVENTS}. 87166f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown */ 87266f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown public void addCallback(int types, Callback cb, int flags) { 87366f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown CallbackInfo info; 87466f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown int index = findCallbackInfo(cb); 87566f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown if (index >= 0) { 87666f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown info = sStatic.mCallbacks.get(index); 87766f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown info.type |= types; 87866f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown info.flags |= flags; 87966f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown } else { 88066f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown info = new CallbackInfo(cb, types, flags, this); 88166f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown sStatic.mCallbacks.add(info); 88266f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown } 88369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown sStatic.updateDiscoveryRequest(); 8849a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 8859a1de308cea2d160778fd977825f10a07b49d738Adam Powell 8869a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 8879a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Remove the specified callback. It will no longer receive events about media routing. 8889a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 8899a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param cb Callback to remove 8909a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 8919a1de308cea2d160778fd977825f10a07b49d738Adam Powell public void removeCallback(Callback cb) { 89266f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown int index = findCallbackInfo(cb); 89366f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown if (index >= 0) { 89469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown sStatic.mCallbacks.remove(index); 89569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown sStatic.updateDiscoveryRequest(); 89666f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown } else { 89766f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown Log.w(TAG, "removeCallback(" + cb + "): callback not registered"); 89866f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown } 89966f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown } 90066f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown 90166f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown private int findCallbackInfo(Callback cb) { 902b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn final int count = sStatic.mCallbacks.size(); 9039a1de308cea2d160778fd977825f10a07b49d738Adam Powell for (int i = 0; i < count; i++) { 90466f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown final CallbackInfo info = sStatic.mCallbacks.get(i); 90566f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown if (info.cb == cb) { 90666f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown return i; 9079a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 9089a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 90966f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown return -1; 9109a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 9119a1de308cea2d160778fd977825f10a07b49d738Adam Powell 912d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell /** 913d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * Select the specified route to use for output of the given media types. 9143afc18af2cea898753b10e8575dcf20c11356bcaJeff Brown * <p class="note"> 9153afc18af2cea898753b10e8575dcf20c11356bcaJeff Brown * As API version 18, this function may be used to select any route. 9163afc18af2cea898753b10e8575dcf20c11356bcaJeff Brown * In prior versions, this function could only be used to select user 9173afc18af2cea898753b10e8575dcf20c11356bcaJeff Brown * routes and would ignore any attempt to select a system route. 9183afc18af2cea898753b10e8575dcf20c11356bcaJeff Brown * </p> 919d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * 920d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param types type flags indicating which types this route should be used for. 921d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * The route must support at least a subset. 922d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param route Route to select 9239d93a378c5158d14f80d46af70433234330ec568P.Y. Laligand * @throws IllegalArgumentException if the given route is {@code null} 924d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell */ 9259d93a378c5158d14f80d46af70433234330ec568P.Y. Laligand public void selectRoute(int types, @NonNull RouteInfo route) { 9269d93a378c5158d14f80d46af70433234330ec568P.Y. Laligand if (route == null) { 9279d93a378c5158d14f80d46af70433234330ec568P.Y. Laligand throw new IllegalArgumentException("Route cannot be null."); 9289d93a378c5158d14f80d46af70433234330ec568P.Y. Laligand } 92969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown selectRouteStatic(types, route, true); 9300d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell } 93169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 9320d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell /** 9330d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * @hide internal use 9340d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell */ 93569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public void selectRouteInt(int types, RouteInfo route, boolean explicit) { 93669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown selectRouteStatic(types, route, explicit); 937b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn } 938b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn 9399d93a378c5158d14f80d46af70433234330ec568P.Y. Laligand static void selectRouteStatic(int types, @NonNull RouteInfo route, boolean explicit) { 94018687b7a275b3782e63d52cdbe8ee9df191046e7Jae Seo Log.v(TAG, "Selecting route: " + route); 9419d93a378c5158d14f80d46af70433234330ec568P.Y. Laligand assert(route != null); 942705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell final RouteInfo oldRoute = sStatic.mSelectedRoute; 943b3658569e9a87afe1b3168837cc282235fd4d1f8Sungsoo boolean wasDefaultOrBluetoothRoute = (oldRoute == sStatic.mDefaultAudioVideo 944b3658569e9a87afe1b3168837cc282235fd4d1f8Sungsoo || oldRoute == sStatic.mBluetoothA2dpRoute); 945b3658569e9a87afe1b3168837cc282235fd4d1f8Sungsoo if (oldRoute == route 94676512a3d80dff2d32b68f3b3b6a14d4ed81ae90aSungsoo Lim && (!wasDefaultOrBluetoothRoute || route == sStatic.getCurrentSystemAudioRoute())) { 947b3658569e9a87afe1b3168837cc282235fd4d1f8Sungsoo return; 948b3658569e9a87afe1b3168837cc282235fd4d1f8Sungsoo } 9490abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown if (!route.matchesTypes(types)) { 9500d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell Log.w(TAG, "selectRoute ignored; cannot select route with supported types " + 9510d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell typesToString(route.getSupportedTypes()) + " into route types " + 9520d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell typesToString(types)); 9534ee1f55ce0f4909a7430ab44563a81852f335071Adam Powell return; 9540d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell } 9559a1de308cea2d160778fd977825f10a07b49d738Adam Powell 956fa6f70e225a7370c1ecb21ee7076c9086ecb9e9aSungsoo final RouteInfo btRoute = sStatic.mBluetoothA2dpRoute; 957b3658569e9a87afe1b3168837cc282235fd4d1f8Sungsoo if (sStatic.isPlaybackActive() && btRoute != null && (types & ROUTE_TYPE_LIVE_AUDIO) != 0 958b3658569e9a87afe1b3168837cc282235fd4d1f8Sungsoo && (route == btRoute || route == sStatic.mDefaultAudioVideo)) { 959fa6f70e225a7370c1ecb21ee7076c9086ecb9e9aSungsoo try { 960fa6f70e225a7370c1ecb21ee7076c9086ecb9e9aSungsoo sStatic.mAudioService.setBluetoothA2dpOn(route == btRoute); 96159579ce59d6e2c42e6ea1b389ba7e228aaa9122fSungsoo Lim // TODO: Remove the following logging when no longer needed. 96259579ce59d6e2c42e6ea1b389ba7e228aaa9122fSungsoo Lim if (route != btRoute) { 96359579ce59d6e2c42e6ea1b389ba7e228aaa9122fSungsoo Lim StackTraceElement[] callStack = Thread.currentThread().getStackTrace(); 96459579ce59d6e2c42e6ea1b389ba7e228aaa9122fSungsoo Lim StringBuffer sb = new StringBuffer(); 96559579ce59d6e2c42e6ea1b389ba7e228aaa9122fSungsoo Lim // callStack[3] is the caller of this method. 96659579ce59d6e2c42e6ea1b389ba7e228aaa9122fSungsoo Lim for (int i = 3; i < callStack.length; i++) { 96759579ce59d6e2c42e6ea1b389ba7e228aaa9122fSungsoo Lim StackTraceElement caller = callStack[i]; 96859579ce59d6e2c42e6ea1b389ba7e228aaa9122fSungsoo Lim sb.append(caller.getClassName() + "." + caller.getMethodName() 96959579ce59d6e2c42e6ea1b389ba7e228aaa9122fSungsoo Lim + ":" + caller.getLineNumber()).append(" "); 97059579ce59d6e2c42e6ea1b389ba7e228aaa9122fSungsoo Lim } 97159579ce59d6e2c42e6ea1b389ba7e228aaa9122fSungsoo Lim Log.w(TAG, "Default route is selected while a BT route is available: pkgName=" 97259579ce59d6e2c42e6ea1b389ba7e228aaa9122fSungsoo Lim + sStatic.mPackageName + ", callers=" + sb.toString()); 97359579ce59d6e2c42e6ea1b389ba7e228aaa9122fSungsoo Lim } 974fa6f70e225a7370c1ecb21ee7076c9086ecb9e9aSungsoo } catch (RemoteException e) { 975fa6f70e225a7370c1ecb21ee7076c9086ecb9e9aSungsoo Log.e(TAG, "Error changing Bluetooth A2DP state", e); 976fa6f70e225a7370c1ecb21ee7076c9086ecb9e9aSungsoo } 977fa6f70e225a7370c1ecb21ee7076c9086ecb9e9aSungsoo } 978fa6f70e225a7370c1ecb21ee7076c9086ecb9e9aSungsoo 979705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell final WifiDisplay activeDisplay = 980705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell sStatic.mDisplayService.getWifiDisplayStatus().getActiveDisplay(); 981705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell final boolean oldRouteHasAddress = oldRoute != null && oldRoute.mDeviceAddress != null; 9829d93a378c5158d14f80d46af70433234330ec568P.Y. Laligand final boolean newRouteHasAddress = route.mDeviceAddress != null; 983705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell if (activeDisplay != null || oldRouteHasAddress || newRouteHasAddress) { 984705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell if (newRouteHasAddress && !matchesDeviceAddress(activeDisplay, route)) { 985af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown if (sStatic.mCanConfigureWifiDisplays) { 986af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown sStatic.mDisplayService.connectWifiDisplay(route.mDeviceAddress); 987af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown } else { 988af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown Log.e(TAG, "Cannot connect to wifi displays because this process " 989af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown + "is not allowed to do so."); 990af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown } 991705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } else if (activeDisplay != null && !newRouteHasAddress) { 992705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell sStatic.mDisplayService.disconnectWifiDisplay(); 993705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 994705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 995705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 99669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown sStatic.setSelectedRoute(route, explicit); 99769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 998705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell if (oldRoute != null) { 999705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell dispatchRouteUnselected(types & oldRoute.getSupportedTypes(), oldRoute); 100039ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown if (oldRoute.resolveStatusCode()) { 100139ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown dispatchRouteChanged(oldRoute); 100239ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown } 10039a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 10049a1de308cea2d160778fd977825f10a07b49d738Adam Powell if (route != null) { 100539ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown if (route.resolveStatusCode()) { 100639ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown dispatchRouteChanged(route); 100739ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown } 10089a1de308cea2d160778fd977825f10a07b49d738Adam Powell dispatchRouteSelected(types & route.getSupportedTypes(), route); 10099a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 1010ce468a35b388ca46578934706b38dbae94941643Jeff Brown 1011ce468a35b388ca46578934706b38dbae94941643Jeff Brown // The behavior of active scans may depend on the currently selected route. 1012ce468a35b388ca46578934706b38dbae94941643Jeff Brown sStatic.updateDiscoveryRequest(); 10139a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 10149a1de308cea2d160778fd977825f10a07b49d738Adam Powell 101569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown static void selectDefaultRouteStatic() { 101669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // TODO: Be smarter about the route types here; this selects for all valid. 101769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (sStatic.mSelectedRoute != sStatic.mBluetoothA2dpRoute 1018fa6f70e225a7370c1ecb21ee7076c9086ecb9e9aSungsoo && sStatic.mBluetoothA2dpRoute != null && sStatic.isBluetoothA2dpOn()) { 101969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown selectRouteStatic(ROUTE_TYPE_ANY, sStatic.mBluetoothA2dpRoute, false); 102069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } else { 102169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown selectRouteStatic(ROUTE_TYPE_ANY, sStatic.mDefaultAudioVideo, false); 102269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 102369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 102469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 10259a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 1026705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell * Compare the device address of a display and a route. 1027705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell * Nulls/no device address will match another null/no address. 1028705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell */ 1029705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell static boolean matchesDeviceAddress(WifiDisplay display, RouteInfo info) { 1030705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell final boolean routeHasAddress = info != null && info.mDeviceAddress != null; 1031705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell if (display == null && !routeHasAddress) { 1032705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell return true; 1033705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1034705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 1035705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell if (display != null && routeHasAddress) { 1036705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell return display.getDeviceAddress().equals(info.mDeviceAddress); 1037705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1038705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell return false; 1039705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1040705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 1041705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell /** 10429a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Add an app-specified route for media to the MediaRouter. 10439a1de308cea2d160778fd977825f10a07b49d738Adam Powell * App-specified route definitions are created using {@link #createUserRoute(RouteCategory)} 10449a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 10459a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param info Definition of the route to add 10463afc18af2cea898753b10e8575dcf20c11356bcaJeff Brown * @see #createUserRoute(RouteCategory) 10479a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @see #removeUserRoute(UserRouteInfo) 10489a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 10499a1de308cea2d160778fd977825f10a07b49d738Adam Powell public void addUserRoute(UserRouteInfo info) { 10502ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell addRouteStatic(info); 10519a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 10529a1de308cea2d160778fd977825f10a07b49d738Adam Powell 1053d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell /** 1054d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell * @hide Framework use only 1055d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell */ 1056d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell public void addRouteInt(RouteInfo info) { 10572ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell addRouteStatic(info); 1058d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell } 1059d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell 10602ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell static void addRouteStatic(RouteInfo info) { 106118687b7a275b3782e63d52cdbe8ee9df191046e7Jae Seo Log.v(TAG, "Adding route: " + info); 10629a1de308cea2d160778fd977825f10a07b49d738Adam Powell final RouteCategory cat = info.getCategory(); 1063b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn if (!sStatic.mCategories.contains(cat)) { 1064b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn sStatic.mCategories.add(cat); 10659a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 1066d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell if (cat.isGroupable() && !(info instanceof RouteGroup)) { 10679a1de308cea2d160778fd977825f10a07b49d738Adam Powell // Enforce that any added route in a groupable category must be in a group. 10689a1de308cea2d160778fd977825f10a07b49d738Adam Powell final RouteGroup group = new RouteGroup(info.getCategory()); 1069dbbfa702a09f6d2d36dee1b552442d04a4673f89Adam Powell group.mSupportedTypes = info.mSupportedTypes; 1070b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn sStatic.mRoutes.add(group); 1071d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell dispatchRouteAdded(group); 1072b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell group.addRoute(info); 1073d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell 10749a1de308cea2d160778fd977825f10a07b49d738Adam Powell info = group; 1075d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell } else { 1076b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn sStatic.mRoutes.add(info); 1077d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell dispatchRouteAdded(info); 10789a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 10799a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 10809a1de308cea2d160778fd977825f10a07b49d738Adam Powell 10819a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 10829a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Remove an app-specified route for media from the MediaRouter. 10839a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 10849a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param info Definition of the route to remove 10859a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @see #addUserRoute(UserRouteInfo) 10869a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 10879a1de308cea2d160778fd977825f10a07b49d738Adam Powell public void removeUserRoute(UserRouteInfo info) { 108869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown removeRouteStatic(info); 10899a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 10909a1de308cea2d160778fd977825f10a07b49d738Adam Powell 1091690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell /** 1092690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell * Remove all app-specified routes from the MediaRouter. 1093690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell * 1094690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell * @see #removeUserRoute(UserRouteInfo) 1095690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell */ 1096690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell public void clearUserRoutes() { 1097b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn for (int i = 0; i < sStatic.mRoutes.size(); i++) { 1098b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn final RouteInfo info = sStatic.mRoutes.get(i); 1099d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell // TODO Right now, RouteGroups only ever contain user routes. 1100d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell // The code below will need to change if this assumption does. 1101d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell if (info instanceof UserRouteInfo || info instanceof RouteGroup) { 110269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown removeRouteStatic(info); 1103690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell i--; 1104690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell } 1105690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell } 1106690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell } 1107690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell 1108d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell /** 1109d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell * @hide internal use only 1110d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell */ 1111d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell public void removeRouteInt(RouteInfo info) { 111269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown removeRouteStatic(info); 1113d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell } 1114d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell 111569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown static void removeRouteStatic(RouteInfo info) { 111618687b7a275b3782e63d52cdbe8ee9df191046e7Jae Seo Log.v(TAG, "Removing route: " + info); 1117b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn if (sStatic.mRoutes.remove(info)) { 11189a1de308cea2d160778fd977825f10a07b49d738Adam Powell final RouteCategory removingCat = info.getCategory(); 1119b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn final int count = sStatic.mRoutes.size(); 11209a1de308cea2d160778fd977825f10a07b49d738Adam Powell boolean found = false; 11219a1de308cea2d160778fd977825f10a07b49d738Adam Powell for (int i = 0; i < count; i++) { 1122b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn final RouteCategory cat = sStatic.mRoutes.get(i).getCategory(); 11239a1de308cea2d160778fd977825f10a07b49d738Adam Powell if (removingCat == cat) { 11249a1de308cea2d160778fd977825f10a07b49d738Adam Powell found = true; 11259a1de308cea2d160778fd977825f10a07b49d738Adam Powell break; 11269a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 11279a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 11280abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown if (info.isSelected()) { 1129d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell // Removing the currently selected route? Select the default before we remove it. 113069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown selectDefaultRouteStatic(); 1131d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell } 1132690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell if (!found) { 1133b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn sStatic.mCategories.remove(removingCat); 1134690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell } 1135690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell dispatchRouteRemoved(info); 1136690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell } 1137690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell } 1138690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell 11399a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 11409a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Return the number of {@link MediaRouter.RouteCategory categories} currently 11419a1de308cea2d160778fd977825f10a07b49d738Adam Powell * represented by routes known to this MediaRouter. 11429a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 11439a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @return the number of unique categories represented by this MediaRouter's known routes 11449a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 11459a1de308cea2d160778fd977825f10a07b49d738Adam Powell public int getCategoryCount() { 1146b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn return sStatic.mCategories.size(); 11479a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 11489a1de308cea2d160778fd977825f10a07b49d738Adam Powell 11499a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 11509a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Return the {@link MediaRouter.RouteCategory category} at the given index. 11519a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Valid indices are in the range [0-getCategoryCount). 11529a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 11539a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param index which category to return 11549a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @return the category at index 11559a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 11569a1de308cea2d160778fd977825f10a07b49d738Adam Powell public RouteCategory getCategoryAt(int index) { 1157b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn return sStatic.mCategories.get(index); 11589a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 11599a1de308cea2d160778fd977825f10a07b49d738Adam Powell 11609a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 11619a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Return the number of {@link MediaRouter.RouteInfo routes} currently known 11629a1de308cea2d160778fd977825f10a07b49d738Adam Powell * to this MediaRouter. 11639a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 11649a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @return the number of routes tracked by this router 11659a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 11669a1de308cea2d160778fd977825f10a07b49d738Adam Powell public int getRouteCount() { 1167b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn return sStatic.mRoutes.size(); 11689a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 11699a1de308cea2d160778fd977825f10a07b49d738Adam Powell 11709a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 11719a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Return the route at the specified index. 11729a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 11739a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param index index of the route to return 11749a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @return the route at index 11759a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 11769a1de308cea2d160778fd977825f10a07b49d738Adam Powell public RouteInfo getRouteAt(int index) { 1177b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn return sStatic.mRoutes.get(index); 1178b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn } 1179b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn 1180b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn static int getRouteCountStatic() { 1181b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn return sStatic.mRoutes.size(); 1182b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn } 1183b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn 1184b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn static RouteInfo getRouteAtStatic(int index) { 1185b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn return sStatic.mRoutes.get(index); 11869a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 11879a1de308cea2d160778fd977825f10a07b49d738Adam Powell 11889a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 11899a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Create a new user route that may be modified and registered for use by the application. 11909a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 11919a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param category The category the new route will belong to 11929a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @return A new UserRouteInfo for use by the application 11939a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 11949a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @see #addUserRoute(UserRouteInfo) 11959a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @see #removeUserRoute(UserRouteInfo) 119669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * @see #createRouteCategory(CharSequence, boolean) 11979a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 11989a1de308cea2d160778fd977825f10a07b49d738Adam Powell public UserRouteInfo createUserRoute(RouteCategory category) { 11999a1de308cea2d160778fd977825f10a07b49d738Adam Powell return new UserRouteInfo(category); 12009a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 12019a1de308cea2d160778fd977825f10a07b49d738Adam Powell 12029a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 12039a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Create a new route category. Each route must belong to a category. 12049a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 12059a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param name Name of the new category 12069a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param isGroupable true if routes in this category may be grouped with one another 12079a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @return the new RouteCategory 12089a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 12099a1de308cea2d160778fd977825f10a07b49d738Adam Powell public RouteCategory createRouteCategory(CharSequence name, boolean isGroupable) { 12109a1de308cea2d160778fd977825f10a07b49d738Adam Powell return new RouteCategory(name, ROUTE_TYPE_USER, isGroupable); 12119a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 12125d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik 12130d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell /** 12140d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * Create a new route category. Each route must belong to a category. 12150d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * 12160d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * @param nameResId Resource ID of the name of the new category 12170d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * @param isGroupable true if routes in this category may be grouped with one another 12180d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * @return the new RouteCategory 12190d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell */ 12200d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public RouteCategory createRouteCategory(int nameResId, boolean isGroupable) { 12210d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell return new RouteCategory(nameResId, ROUTE_TYPE_USER, isGroupable); 12220d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell } 12239a1de308cea2d160778fd977825f10a07b49d738Adam Powell 122469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown /** 122569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * Rebinds the media router to handle routes that belong to the specified user. 122669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * Requires the interact across users permission to access the routes of another user. 122769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * <p> 122869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * This method is a complete hack to work around the singleton nature of the 122969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * media router when running inside of singleton processes like QuickSettings. 123069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * This mechanism should be burned to the ground when MediaRouter is redesigned. 123169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * Ideally the current user would be pulled from the Context but we need to break 123269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * down MediaRouter.Static before we can get there. 123369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * </p> 123469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * 123569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * @hide 123669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown */ 123769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public void rebindAsUser(int userId) { 123869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown sStatic.rebindAsUser(userId); 123969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 124069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 1241b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn static void updateRoute(final RouteInfo info) { 12429a1de308cea2d160778fd977825f10a07b49d738Adam Powell dispatchRouteChanged(info); 12439a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 12449a1de308cea2d160778fd977825f10a07b49d738Adam Powell 1245b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn static void dispatchRouteSelected(int type, RouteInfo info) { 124639d5c6172503620ac3761148adac5fd7fa20d02dAdam Powell for (CallbackInfo cbi : sStatic.mCallbacks) { 124766f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown if (cbi.filterRouteEvent(info)) { 1248b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn cbi.cb.onRouteSelected(cbi.router, type, info); 12499a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 12509a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 12519a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 12529a1de308cea2d160778fd977825f10a07b49d738Adam Powell 1253b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn static void dispatchRouteUnselected(int type, RouteInfo info) { 125439d5c6172503620ac3761148adac5fd7fa20d02dAdam Powell for (CallbackInfo cbi : sStatic.mCallbacks) { 125566f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown if (cbi.filterRouteEvent(info)) { 1256b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn cbi.cb.onRouteUnselected(cbi.router, type, info); 12579a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 12589a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 12599a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 12609a1de308cea2d160778fd977825f10a07b49d738Adam Powell 1261b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn static void dispatchRouteChanged(RouteInfo info) { 1262af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown dispatchRouteChanged(info, info.mSupportedTypes); 1263af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown } 1264af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown 1265af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown static void dispatchRouteChanged(RouteInfo info, int oldSupportedTypes) { 12664bad663518908c20ed4f93a27f46ffb09448497fSungsoo Lim if (DEBUG) { 12674bad663518908c20ed4f93a27f46ffb09448497fSungsoo Lim Log.d(TAG, "Dispatching route change: " + info); 12684bad663518908c20ed4f93a27f46ffb09448497fSungsoo Lim } 1269af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown final int newSupportedTypes = info.mSupportedTypes; 127039d5c6172503620ac3761148adac5fd7fa20d02dAdam Powell for (CallbackInfo cbi : sStatic.mCallbacks) { 1271af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown // Reconstruct some of the history for callbacks that may not have observed 1272af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown // all of the events needed to correctly interpret the current state. 1273af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown // FIXME: This is a strong signal that we should deprecate route type filtering 1274af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown // completely in the future because it can lead to inconsistencies in 1275af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown // applications. 1276af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown final boolean oldVisibility = cbi.filterRouteEvent(oldSupportedTypes); 1277af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown final boolean newVisibility = cbi.filterRouteEvent(newSupportedTypes); 1278af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown if (!oldVisibility && newVisibility) { 1279af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown cbi.cb.onRouteAdded(cbi.router, info); 1280af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown if (info.isSelected()) { 1281af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown cbi.cb.onRouteSelected(cbi.router, newSupportedTypes, info); 1282af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown } 1283af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown } 1284af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown if (oldVisibility || newVisibility) { 1285b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn cbi.cb.onRouteChanged(cbi.router, info); 12869a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 1287af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown if (oldVisibility && !newVisibility) { 1288af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown if (info.isSelected()) { 1289af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown cbi.cb.onRouteUnselected(cbi.router, oldSupportedTypes, info); 1290af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown } 1291af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown cbi.cb.onRouteRemoved(cbi.router, info); 1292af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown } 12939a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 12949a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 12959a1de308cea2d160778fd977825f10a07b49d738Adam Powell 1296b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn static void dispatchRouteAdded(RouteInfo info) { 129739d5c6172503620ac3761148adac5fd7fa20d02dAdam Powell for (CallbackInfo cbi : sStatic.mCallbacks) { 129866f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown if (cbi.filterRouteEvent(info)) { 1299b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn cbi.cb.onRouteAdded(cbi.router, info); 13009a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 13019a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 13029a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 13039a1de308cea2d160778fd977825f10a07b49d738Adam Powell 1304b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn static void dispatchRouteRemoved(RouteInfo info) { 130539d5c6172503620ac3761148adac5fd7fa20d02dAdam Powell for (CallbackInfo cbi : sStatic.mCallbacks) { 130666f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown if (cbi.filterRouteEvent(info)) { 1307b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn cbi.cb.onRouteRemoved(cbi.router, info); 13089a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 13099a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 13109a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 13119a1de308cea2d160778fd977825f10a07b49d738Adam Powell 1312b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn static void dispatchRouteGrouped(RouteInfo info, RouteGroup group, int index) { 131339d5c6172503620ac3761148adac5fd7fa20d02dAdam Powell for (CallbackInfo cbi : sStatic.mCallbacks) { 131466f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown if (cbi.filterRouteEvent(group)) { 1315b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn cbi.cb.onRouteGrouped(cbi.router, info, group, index); 1316d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell } 1317d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell } 1318d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell } 1319d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell 1320b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn static void dispatchRouteUngrouped(RouteInfo info, RouteGroup group) { 132139d5c6172503620ac3761148adac5fd7fa20d02dAdam Powell for (CallbackInfo cbi : sStatic.mCallbacks) { 132266f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown if (cbi.filterRouteEvent(group)) { 1323b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn cbi.cb.onRouteUngrouped(cbi.router, info, group); 13249a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 13259a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 13269a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 13279a1de308cea2d160778fd977825f10a07b49d738Adam Powell 13288e37a85bf3dc39519942698dc90a3951306b934bAdam Powell static void dispatchRouteVolumeChanged(RouteInfo info) { 13298e37a85bf3dc39519942698dc90a3951306b934bAdam Powell for (CallbackInfo cbi : sStatic.mCallbacks) { 133066f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown if (cbi.filterRouteEvent(info)) { 13318e37a85bf3dc39519942698dc90a3951306b934bAdam Powell cbi.cb.onRouteVolumeChanged(cbi.router, info); 13328e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 13338e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 13348e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 13358e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 133692130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown static void dispatchRoutePresentationDisplayChanged(RouteInfo info) { 133792130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown for (CallbackInfo cbi : sStatic.mCallbacks) { 133866f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown if (cbi.filterRouteEvent(info)) { 133992130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown cbi.cb.onRoutePresentationDisplayChanged(cbi.router, info); 134092130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown } 134192130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown } 134292130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown } 134392130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown 13448e37a85bf3dc39519942698dc90a3951306b934bAdam Powell static void systemVolumeChanged(int newValue) { 13458e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final RouteInfo selectedRoute = sStatic.mSelectedRoute; 13468e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (selectedRoute == null) return; 13478e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 13488e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (selectedRoute == sStatic.mBluetoothA2dpRoute || 1349705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell selectedRoute == sStatic.mDefaultAudioVideo) { 13508e37a85bf3dc39519942698dc90a3951306b934bAdam Powell dispatchRouteVolumeChanged(selectedRoute); 13518e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } else if (sStatic.mBluetoothA2dpRoute != null) { 1352fa6f70e225a7370c1ecb21ee7076c9086ecb9e9aSungsoo try { 1353fa6f70e225a7370c1ecb21ee7076c9086ecb9e9aSungsoo dispatchRouteVolumeChanged(sStatic.mAudioService.isBluetoothA2dpOn() ? 1354fa6f70e225a7370c1ecb21ee7076c9086ecb9e9aSungsoo sStatic.mBluetoothA2dpRoute : sStatic.mDefaultAudioVideo); 1355fa6f70e225a7370c1ecb21ee7076c9086ecb9e9aSungsoo } catch (RemoteException e) { 1356fa6f70e225a7370c1ecb21ee7076c9086ecb9e9aSungsoo Log.e(TAG, "Error checking Bluetooth A2DP state to report volume change", e); 1357fa6f70e225a7370c1ecb21ee7076c9086ecb9e9aSungsoo } 13588e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } else { 1359705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell dispatchRouteVolumeChanged(sStatic.mDefaultAudioVideo); 1360705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1361705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1362705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 136375af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown static void updateWifiDisplayStatus(WifiDisplayStatus status) { 136475af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown WifiDisplay[] displays; 1365615e413a90ff5898d8c458ebc9649ca95fa9fd98Adam Powell WifiDisplay activeDisplay; 136675af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown if (status.getFeatureState() == WifiDisplayStatus.FEATURE_STATE_ON) { 136775af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown displays = status.getDisplays(); 136875af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown activeDisplay = status.getActiveDisplay(); 1369af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown 1370af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown // Only the system is able to connect to wifi display routes. 1371af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown // The display manager will enforce this with a permission check but it 1372af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown // still publishes information about all available displays. 1373af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown // Filter the list down to just the active display. 1374af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown if (!sStatic.mCanConfigureWifiDisplays) { 1375af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown if (activeDisplay != null) { 1376af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown displays = new WifiDisplay[] { activeDisplay }; 1377af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown } else { 1378af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown displays = WifiDisplay.EMPTY_ARRAY; 1379af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown } 1380af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown } 1381615e413a90ff5898d8c458ebc9649ca95fa9fd98Adam Powell } else { 138275af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown displays = WifiDisplay.EMPTY_ARRAY; 1383615e413a90ff5898d8c458ebc9649ca95fa9fd98Adam Powell activeDisplay = null; 1384615e413a90ff5898d8c458ebc9649ca95fa9fd98Adam Powell } 1385ce468a35b388ca46578934706b38dbae94941643Jeff Brown String activeDisplayAddress = activeDisplay != null ? 1386ce468a35b388ca46578934706b38dbae94941643Jeff Brown activeDisplay.getDeviceAddress() : null; 1387705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 138875af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown // Add or update routes. 138975af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown for (int i = 0; i < displays.length; i++) { 139075af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown final WifiDisplay d = displays[i]; 139175af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown if (shouldShowWifiDisplay(d, activeDisplay)) { 1392ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang RouteInfo route = findWifiDisplayRoute(d); 1393ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang if (route == null) { 139475af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown route = makeWifiDisplayRoute(d, status); 1395ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang addRouteStatic(route); 1396ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang } else { 1397ce468a35b388ca46578934706b38dbae94941643Jeff Brown String address = d.getDeviceAddress(); 1398ce468a35b388ca46578934706b38dbae94941643Jeff Brown boolean disconnected = !address.equals(activeDisplayAddress) 1399ce468a35b388ca46578934706b38dbae94941643Jeff Brown && address.equals(sStatic.mPreviousActiveWifiDisplayAddress); 1400ce468a35b388ca46578934706b38dbae94941643Jeff Brown updateWifiDisplayRoute(route, d, status, disconnected); 1401ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang } 1402ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang if (d.equals(activeDisplay)) { 140369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown selectRouteStatic(route.getSupportedTypes(), route, false); 1404ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang } 14052ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell } 1406705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 140775af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown 140875af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown // Remove stale routes. 140975af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown for (int i = sStatic.mRoutes.size(); i-- > 0; ) { 141075af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown RouteInfo route = sStatic.mRoutes.get(i); 141175af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown if (route.mDeviceAddress != null) { 141275af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown WifiDisplay d = findWifiDisplay(displays, route.mDeviceAddress); 141375af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown if (d == null || !shouldShowWifiDisplay(d, activeDisplay)) { 141475af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown removeRouteStatic(route); 1415ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang } 1416705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1417705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1418ce468a35b388ca46578934706b38dbae94941643Jeff Brown 1419ce468a35b388ca46578934706b38dbae94941643Jeff Brown // Remember the current active wifi display address so that we can infer disconnections. 1420ce468a35b388ca46578934706b38dbae94941643Jeff Brown // TODO: This hack will go away once all of this is moved into the media router service. 1421ce468a35b388ca46578934706b38dbae94941643Jeff Brown sStatic.mPreviousActiveWifiDisplayAddress = activeDisplayAddress; 142275af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown } 1423705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 142475af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown private static boolean shouldShowWifiDisplay(WifiDisplay d, WifiDisplay activeDisplay) { 142575af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown return d.isRemembered() || d.equals(activeDisplay); 1426705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1427705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 1428ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang static int getWifiDisplayStatusCode(WifiDisplay d, WifiDisplayStatus wfdStatus) { 142969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown int newStatus; 1430ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang if (wfdStatus.getScanState() == WifiDisplayStatus.SCAN_STATE_SCANNING) { 1431ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang newStatus = RouteInfo.STATUS_SCANNING; 1432ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang } else if (d.isAvailable()) { 1433ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang newStatus = d.canConnect() ? 1434ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang RouteInfo.STATUS_AVAILABLE: RouteInfo.STATUS_IN_USE; 1435705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } else { 1436705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell newStatus = RouteInfo.STATUS_NOT_AVAILABLE; 1437705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1438705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 1439ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang if (d.equals(wfdStatus.getActiveDisplay())) { 1440ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang final int activeState = wfdStatus.getActiveDisplayState(); 1441705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell switch (activeState) { 1442705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell case WifiDisplayStatus.DISPLAY_STATE_CONNECTED: 144369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown newStatus = RouteInfo.STATUS_CONNECTED; 1444705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell break; 1445705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell case WifiDisplayStatus.DISPLAY_STATE_CONNECTING: 1446705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell newStatus = RouteInfo.STATUS_CONNECTING; 1447705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell break; 1448705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell case WifiDisplayStatus.DISPLAY_STATE_NOT_CONNECTED: 1449705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell Log.e(TAG, "Active display is not connected!"); 1450705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell break; 1451705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1452705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1453705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 1454ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang return newStatus; 1455ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang } 1456ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang 1457ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang static boolean isWifiDisplayEnabled(WifiDisplay d, WifiDisplayStatus wfdStatus) { 1458ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang return d.isAvailable() && (d.canConnect() || d.equals(wfdStatus.getActiveDisplay())); 1459ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang } 1460ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang 1461ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang static RouteInfo makeWifiDisplayRoute(WifiDisplay display, WifiDisplayStatus wfdStatus) { 1462ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang final RouteInfo newRoute = new RouteInfo(sStatic.mSystemCategory); 1463ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang newRoute.mDeviceAddress = display.getDeviceAddress(); 146469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown newRoute.mSupportedTypes = ROUTE_TYPE_LIVE_AUDIO | ROUTE_TYPE_LIVE_VIDEO 146569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown | ROUTE_TYPE_REMOTE_DISPLAY; 1466ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang newRoute.mVolumeHandling = RouteInfo.PLAYBACK_VOLUME_FIXED; 1467ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang newRoute.mPlaybackType = RouteInfo.PLAYBACK_TYPE_REMOTE; 1468ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang 146939ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown newRoute.setRealStatusCode(getWifiDisplayStatusCode(display, wfdStatus)); 1470ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang newRoute.mEnabled = isWifiDisplayEnabled(display, wfdStatus); 1471ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang newRoute.mName = display.getFriendlyDisplayName(); 1472ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang newRoute.mDescription = sStatic.mResources.getText( 1473ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang com.android.internal.R.string.wireless_display_route_description); 14745830b0b33618940d65197cec99d697b21908fec8Chong Zhang newRoute.updatePresentationDisplay(); 14759dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang newRoute.mDeviceType = RouteInfo.DEVICE_TYPE_TV; 1476ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang return newRoute; 1477ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang } 1478ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang 1479ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang private static void updateWifiDisplayRoute( 1480ce468a35b388ca46578934706b38dbae94941643Jeff Brown RouteInfo route, WifiDisplay display, WifiDisplayStatus wfdStatus, 1481ce468a35b388ca46578934706b38dbae94941643Jeff Brown boolean disconnected) { 1482ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang boolean changed = false; 14832444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown final String newName = display.getFriendlyDisplayName(); 14842444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown if (!route.getName().equals(newName)) { 1485705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell route.mName = newName; 1486705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell changed = true; 1487705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1488705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 1489ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang boolean enabled = isWifiDisplayEnabled(display, wfdStatus); 1490ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang changed |= route.mEnabled != enabled; 1491ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang route.mEnabled = enabled; 1492705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 149339ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown changed |= route.setRealStatusCode(getWifiDisplayStatusCode(display, wfdStatus)); 1494705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 1495705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell if (changed) { 1496705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell dispatchRouteChanged(route); 1497705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1498705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 1499ce468a35b388ca46578934706b38dbae94941643Jeff Brown if ((!enabled || disconnected) && route.isSelected()) { 1500705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell // Oops, no longer available. Reselect the default. 150169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown selectDefaultRouteStatic(); 1502705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1503705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1504705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 150575af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown private static WifiDisplay findWifiDisplay(WifiDisplay[] displays, String deviceAddress) { 1506705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell for (int i = 0; i < displays.length; i++) { 150775af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown final WifiDisplay d = displays[i]; 150875af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown if (d.getDeviceAddress().equals(deviceAddress)) { 150975af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown return d; 1510705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1511705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1512705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell return null; 1513705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1514705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 1515705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell private static RouteInfo findWifiDisplayRoute(WifiDisplay d) { 1516705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell final int count = sStatic.mRoutes.size(); 1517705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell for (int i = 0; i < count; i++) { 1518705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell final RouteInfo info = sStatic.mRoutes.get(i); 1519705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell if (d.getDeviceAddress().equals(info.mDeviceAddress)) { 1520705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell return info; 1521705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1522705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1523705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell return null; 15248e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 15258e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 15269a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 15279a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Information about a media route. 15289a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 1529b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn public static class RouteInfo { 15309a1de308cea2d160778fd977825f10a07b49d738Adam Powell CharSequence mName; 15310d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell int mNameResId; 153256d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown CharSequence mDescription; 15339a1de308cea2d160778fd977825f10a07b49d738Adam Powell private CharSequence mStatus; 15349a1de308cea2d160778fd977825f10a07b49d738Adam Powell int mSupportedTypes; 15359dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang int mDeviceType; 15369a1de308cea2d160778fd977825f10a07b49d738Adam Powell RouteGroup mGroup; 15379a1de308cea2d160778fd977825f10a07b49d738Adam Powell final RouteCategory mCategory; 1538ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell Drawable mIcon; 15391357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi // playback information 15401357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi int mPlaybackType = PLAYBACK_TYPE_LOCAL; 15411357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi int mVolumeMax = RemoteControlClient.DEFAULT_PLAYBACK_VOLUME; 15421357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi int mVolume = RemoteControlClient.DEFAULT_PLAYBACK_VOLUME; 15431357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi int mVolumeHandling = RemoteControlClient.DEFAULT_PLAYBACK_VOLUME_HANDLING; 15441357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi int mPlaybackStream = AudioManager.STREAM_MUSIC; 15451357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi VolumeCallbackInfo mVcb; 154692130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown Display mPresentationDisplay; 15475830b0b33618940d65197cec99d697b21908fec8Chong Zhang int mPresentationDisplayId = -1; 15489a1de308cea2d160778fd977825f10a07b49d738Adam Powell 1549705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell String mDeviceAddress; 1550705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell boolean mEnabled = true; 1551705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 155269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // An id by which the route is known to the media router service. 155369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Null if this route only exists as an artifact within this process. 155469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown String mGlobalRouteId; 155569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 1556705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell // A predetermined connection status that can override mStatus 155739ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown private int mRealStatusCode; 155839ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown private int mResolvedStatusCode; 1559705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 15602ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell /** @hide */ public static final int STATUS_NONE = 0; 15612ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell /** @hide */ public static final int STATUS_SCANNING = 1; 15622ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell /** @hide */ public static final int STATUS_CONNECTING = 2; 15632ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell /** @hide */ public static final int STATUS_AVAILABLE = 3; 15642ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell /** @hide */ public static final int STATUS_NOT_AVAILABLE = 4; 1565ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang /** @hide */ public static final int STATUS_IN_USE = 5; 156669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown /** @hide */ public static final int STATUS_CONNECTED = 6; 1567705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 15689dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang /** @hide */ 15699dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang @IntDef({DEVICE_TYPE_UNKNOWN, DEVICE_TYPE_TV, DEVICE_TYPE_SPEAKER, DEVICE_TYPE_BLUETOOTH}) 15709dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang @Retention(RetentionPolicy.SOURCE) 15719dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang public @interface DeviceType {} 15729dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang 15739dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang /** 15749dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang * The default receiver device type of the route indicating the type is unknown. 15759dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang * 15769dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang * @see #getDeviceType 15779dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang */ 15789dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang public static final int DEVICE_TYPE_UNKNOWN = 0; 15799dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang 15809dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang /** 15819dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang * A receiver device type of the route indicating the presentation of the media is happening 15829dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang * on a TV. 15839dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang * 15849dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang * @see #getDeviceType 15859dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang */ 15869dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang public static final int DEVICE_TYPE_TV = 1; 15879dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang 15889dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang /** 15899dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang * A receiver device type of the route indicating the presentation of the media is happening 15909dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang * on a speaker. 15919dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang * 15929dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang * @see #getDeviceType 15939dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang */ 15949dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang public static final int DEVICE_TYPE_SPEAKER = 2; 15959dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang 15969dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang /** 15979dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang * A receiver device type of the route indicating the presentation of the media is happening 15989dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang * on a bluetooth device such as a bluetooth speaker. 15999dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang * 16009dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang * @see #getDeviceType 16019dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang */ 16029dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang public static final int DEVICE_TYPE_BLUETOOTH = 3; 16039dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang 1604b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell private Object mTag; 1605b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell 16067c090d54e2c0eb5309d3f7dc131e137d9c986793Insun Kang /** @hide */ 16077c090d54e2c0eb5309d3f7dc131e137d9c986793Insun Kang @IntDef({PLAYBACK_TYPE_LOCAL, PLAYBACK_TYPE_REMOTE}) 16087c090d54e2c0eb5309d3f7dc131e137d9c986793Insun Kang @Retention(RetentionPolicy.SOURCE) 16097c090d54e2c0eb5309d3f7dc131e137d9c986793Insun Kang public @interface PlaybackType {} 16107c090d54e2c0eb5309d3f7dc131e137d9c986793Insun Kang 16111357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 16121357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * The default playback type, "local", indicating the presentation of the media is happening 1613bc4cf00dc5bf6e0e3c01206d5c46e64306df260aJohn Spurlock * on the same device (e.g. a phone, a tablet) as where it is controlled from. 161469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * @see #getPlaybackType() 16151357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 16161357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public final static int PLAYBACK_TYPE_LOCAL = 0; 16177c090d54e2c0eb5309d3f7dc131e137d9c986793Insun Kang 16181357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 16191357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * A playback type indicating the presentation of the media is happening on 1620bc4cf00dc5bf6e0e3c01206d5c46e64306df260aJohn Spurlock * a different device (i.e. the remote device) than where it is controlled from. 162169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * @see #getPlaybackType() 16221357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 16231357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public final static int PLAYBACK_TYPE_REMOTE = 1; 16247c090d54e2c0eb5309d3f7dc131e137d9c986793Insun Kang 16257c090d54e2c0eb5309d3f7dc131e137d9c986793Insun Kang /** @hide */ 16267c090d54e2c0eb5309d3f7dc131e137d9c986793Insun Kang @IntDef({PLAYBACK_VOLUME_FIXED,PLAYBACK_VOLUME_VARIABLE}) 16277c090d54e2c0eb5309d3f7dc131e137d9c986793Insun Kang @Retention(RetentionPolicy.SOURCE) 16287c090d54e2c0eb5309d3f7dc131e137d9c986793Insun Kang private @interface PlaybackVolume {} 16297c090d54e2c0eb5309d3f7dc131e137d9c986793Insun Kang 16301357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 1631bc4cf00dc5bf6e0e3c01206d5c46e64306df260aJohn Spurlock * Playback information indicating the playback volume is fixed, i.e. it cannot be 16321357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * controlled from this object. An example of fixed playback volume is a remote player, 16331357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * playing over HDMI where the user prefers to control the volume on the HDMI sink, rather 16341357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * than attenuate at the source. 163569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * @see #getVolumeHandling() 16361357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 16371357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public final static int PLAYBACK_VOLUME_FIXED = 0; 16381357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 16391357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * Playback information indicating the playback volume is variable and can be controlled 16401357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * from this object. 164169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * @see #getVolumeHandling() 16421357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 16431357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public final static int PLAYBACK_VOLUME_VARIABLE = 1; 16441357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 16459a1de308cea2d160778fd977825f10a07b49d738Adam Powell RouteInfo(RouteCategory category) { 16469a1de308cea2d160778fd977825f10a07b49d738Adam Powell mCategory = category; 16479dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang mDeviceType = DEVICE_TYPE_UNKNOWN; 16489a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 16499a1de308cea2d160778fd977825f10a07b49d738Adam Powell 16509a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 165156d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * Gets the user-visible name of the route. 165256d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * <p> 165356d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * The route name identifies the destination represented by the route. 165456d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * It may be a user-supplied name, an alias, or device serial number. 165556d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * </p> 165656d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * 165756d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * @return The user-visible name of a media route. This is the string presented 16589a1de308cea2d160778fd977825f10a07b49d738Adam Powell * to users who may select this as the active route. 16599a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 16609a1de308cea2d160778fd977825f10a07b49d738Adam Powell public CharSequence getName() { 16610d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell return getName(sStatic.mResources); 16620d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell } 166356d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown 16640d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell /** 166556d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * Return the properly localized/resource user-visible name of this route. 166656d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * <p> 166756d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * The route name identifies the destination represented by the route. 166856d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * It may be a user-supplied name, an alias, or device serial number. 166956d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * </p> 167056d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * 16710d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * @param context Context used to resolve the correct configuration to load 167256d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * @return The user-visible name of a media route. This is the string presented 16730d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * to users who may select this as the active route. 16740d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell */ 16750d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public CharSequence getName(Context context) { 16760d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell return getName(context.getResources()); 16770d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell } 167856d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown 16790d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell CharSequence getName(Resources res) { 16800d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell if (mNameResId != 0) { 1681eadd6d2329972129c96dee390a8b786b37313d17Hyundo Moon return res.getText(mNameResId); 16820d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell } 16839a1de308cea2d160778fd977825f10a07b49d738Adam Powell return mName; 16849a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 16859a1de308cea2d160778fd977825f10a07b49d738Adam Powell 16869a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 168756d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * Gets the user-visible description of the route. 168856d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * <p> 168956d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * The route description describes the kind of destination represented by the route. 169056d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * It may be a user-supplied string, a model number or brand of device. 169156d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * </p> 169256d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * 169356d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * @return The description of the route, or null if none. 169456d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown */ 169556d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown public CharSequence getDescription() { 169656d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown return mDescription; 169756d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown } 169856d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown 169956d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown /** 170056d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * @return The user-visible status for a media route. This may include a description 17019a1de308cea2d160778fd977825f10a07b49d738Adam Powell * of the currently playing media, if available. 17029a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 17039a1de308cea2d160778fd977825f10a07b49d738Adam Powell public CharSequence getStatus() { 17049a1de308cea2d160778fd977825f10a07b49d738Adam Powell return mStatus; 17059a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 17069a1de308cea2d160778fd977825f10a07b49d738Adam Powell 17079a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 1708705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell * Set this route's status by predetermined status code. If the caller 1709705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell * should dispatch a route changed event this call will return true; 1710705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell */ 171139ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown boolean setRealStatusCode(int statusCode) { 171239ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown if (mRealStatusCode != statusCode) { 171339ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown mRealStatusCode = statusCode; 171439ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown return resolveStatusCode(); 171539ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown } 171639ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown return false; 171739ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown } 171839ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown 171939ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown /** 172039ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown * Resolves the status code whenever the real status code or selection state 172139ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown * changes. 172239ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown */ 172339ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown boolean resolveStatusCode() { 172439ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown int statusCode = mRealStatusCode; 172539ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown if (isSelected()) { 1726705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell switch (statusCode) { 172739ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown // If the route is selected and its status appears to be between states 172839ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown // then report it as connecting even though it has not yet had a chance 172939ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown // to officially move into the CONNECTING state. Note that routes in 173039ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown // the NONE state are assumed to not require an explicit connection 173139ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown // lifecycle whereas those that are AVAILABLE are assumed to have 173239ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown // to eventually proceed to CONNECTED. 1733705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell case STATUS_AVAILABLE: 173439ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown case STATUS_SCANNING: 173539ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown statusCode = STATUS_CONNECTING; 173669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown break; 1737705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1738705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 173939ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown if (mResolvedStatusCode == statusCode) { 174039ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown return false; 174139ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown } 174239ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown 174339ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown mResolvedStatusCode = statusCode; 174439ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown int resId; 174539ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown switch (statusCode) { 174639ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown case STATUS_SCANNING: 174739ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown resId = com.android.internal.R.string.media_route_status_scanning; 174839ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown break; 174939ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown case STATUS_CONNECTING: 175039ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown resId = com.android.internal.R.string.media_route_status_connecting; 175139ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown break; 175239ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown case STATUS_AVAILABLE: 175339ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown resId = com.android.internal.R.string.media_route_status_available; 175439ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown break; 175539ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown case STATUS_NOT_AVAILABLE: 175639ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown resId = com.android.internal.R.string.media_route_status_not_available; 175739ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown break; 175839ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown case STATUS_IN_USE: 175939ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown resId = com.android.internal.R.string.media_route_status_in_use; 176039ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown break; 176139ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown case STATUS_CONNECTED: 176239ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown case STATUS_NONE: 176339ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown default: 176439ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown resId = 0; 176539ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown break; 176639ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown } 176739ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown mStatus = resId != 0 ? sStatic.mResources.getText(resId) : null; 176839ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown return true; 1769705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1770705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 1771705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell /** 17722ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell * @hide 17732ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell */ 17742ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell public int getStatusCode() { 177539ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown return mResolvedStatusCode; 17762ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell } 17772ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell 17782ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell /** 17799a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @return A media type flag set describing which types this route supports. 17809a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 17819a1de308cea2d160778fd977825f10a07b49d738Adam Powell public int getSupportedTypes() { 17829a1de308cea2d160778fd977825f10a07b49d738Adam Powell return mSupportedTypes; 17839a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 17849a1de308cea2d160778fd977825f10a07b49d738Adam Powell 17859dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang /** 17869dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang * Gets the type of the receiver device associated with this route. 17879dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang * 17889dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang * @return The type of the receiver device associated with this route: 17899dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang * {@link #DEVICE_TYPE_BLUETOOTH}, {@link #DEVICE_TYPE_TV}, {@link #DEVICE_TYPE_SPEAKER}, 17909dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang * or {@link #DEVICE_TYPE_UNKNOWN}. 17919dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang */ 17929dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang @DeviceType 17939dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang public int getDeviceType() { 17949dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang return mDeviceType; 17959dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang } 17969dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang 17970abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown /** @hide */ 17980abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown public boolean matchesTypes(int types) { 17990abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown return (mSupportedTypes & types) != 0; 18000abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown } 18010abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown 18029a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 18039a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @return The group that this route belongs to. 18049a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 18059a1de308cea2d160778fd977825f10a07b49d738Adam Powell public RouteGroup getGroup() { 18069a1de308cea2d160778fd977825f10a07b49d738Adam Powell return mGroup; 18079a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 18089a1de308cea2d160778fd977825f10a07b49d738Adam Powell 18099a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 18109a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @return the category this route belongs to. 18119a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 18129a1de308cea2d160778fd977825f10a07b49d738Adam Powell public RouteCategory getCategory() { 18139a1de308cea2d160778fd977825f10a07b49d738Adam Powell return mCategory; 18149a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 18159a1de308cea2d160778fd977825f10a07b49d738Adam Powell 1816ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell /** 1817ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * Get the icon representing this route. 1818ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * This icon will be used in picker UIs if available. 1819ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * 1820ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * @return the icon representing this route or null if no icon is available 1821ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell */ 1822ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell public Drawable getIconDrawable() { 1823ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell return mIcon; 1824ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell } 1825ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell 1826b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell /** 1827b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell * Set an application-specific tag object for this route. 1828b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell * The application may use this to store arbitrary data associated with the 1829b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell * route for internal tracking. 1830b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell * 1831b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell * <p>Note that the lifespan of a route may be well past the lifespan of 1832b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell * an Activity or other Context; take care that objects you store here 1833b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell * will not keep more data in memory alive than you intend.</p> 1834b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell * 1835b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell * @param tag Arbitrary, app-specific data for this route to hold for later use 1836b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell */ 1837b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell public void setTag(Object tag) { 1838b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell mTag = tag; 1839130b4572d1f3df702e5b296a655d15a41f6d4c66Adam Powell routeUpdated(); 1840b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell } 1841b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell 1842b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell /** 1843b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell * @return The tag object previously set by the application 1844b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell * @see #setTag(Object) 1845b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell */ 1846b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell public Object getTag() { 1847b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell return mTag; 1848b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell } 1849b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell 18501357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 18511357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @return the type of playback associated with this route 18521357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @see UserRouteInfo#setPlaybackType(int) 18531357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 18547c090d54e2c0eb5309d3f7dc131e137d9c986793Insun Kang @PlaybackType 18551357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public int getPlaybackType() { 18561357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi return mPlaybackType; 18571357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 18581357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 18591357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 18601357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @return the stream over which the playback associated with this route is performed 18611357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @see UserRouteInfo#setPlaybackStream(int) 18621357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 18631357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public int getPlaybackStream() { 18641357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi return mPlaybackStream; 18651357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 18661357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 18671357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 18688e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * Return the current volume for this route. Depending on the route, this may only 18698e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * be valid if the route is currently selected. 18708e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * 18711357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @return the volume at which the playback associated with this route is performed 18721357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @see UserRouteInfo#setVolume(int) 18731357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 18741357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public int getVolume() { 18751357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi if (mPlaybackType == PLAYBACK_TYPE_LOCAL) { 18761357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi int vol = 0; 18771357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi try { 18781357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi vol = sStatic.mAudioService.getStreamVolume(mPlaybackStream); 18791357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } catch (RemoteException e) { 18801357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi Log.e(TAG, "Error getting local stream volume", e); 18811357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 18821357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi return vol; 18831357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } else { 18841357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi return mVolume; 18851357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 18861357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 18871357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 18881357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 18898e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * Request a volume change for this route. 18908e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * @param volume value between 0 and getVolumeMax 18918e37a85bf3dc39519942698dc90a3951306b934bAdam Powell */ 18928e37a85bf3dc39519942698dc90a3951306b934bAdam Powell public void requestSetVolume(int volume) { 18938e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (mPlaybackType == PLAYBACK_TYPE_LOCAL) { 18948e37a85bf3dc39519942698dc90a3951306b934bAdam Powell try { 1895ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn sStatic.mAudioService.setStreamVolume(mPlaybackStream, volume, 0, 1896ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn ActivityThread.currentPackageName()); 18978e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } catch (RemoteException e) { 18988e37a85bf3dc39519942698dc90a3951306b934bAdam Powell Log.e(TAG, "Error setting local stream volume", e); 18998e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 19008e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } else { 190169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown sStatic.requestSetVolume(this, volume); 19028e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 19038e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 19048e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 19058e37a85bf3dc39519942698dc90a3951306b934bAdam Powell /** 19068e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * Request an incremental volume update for this route. 19078e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * @param direction Delta to apply to the current volume 19088e37a85bf3dc39519942698dc90a3951306b934bAdam Powell */ 19098e37a85bf3dc39519942698dc90a3951306b934bAdam Powell public void requestUpdateVolume(int direction) { 19108e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (mPlaybackType == PLAYBACK_TYPE_LOCAL) { 19118e37a85bf3dc39519942698dc90a3951306b934bAdam Powell try { 19128e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final int volume = 19138e37a85bf3dc39519942698dc90a3951306b934bAdam Powell Math.max(0, Math.min(getVolume() + direction, getVolumeMax())); 1914ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn sStatic.mAudioService.setStreamVolume(mPlaybackStream, volume, 0, 1915ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn ActivityThread.currentPackageName()); 19168e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } catch (RemoteException e) { 19178e37a85bf3dc39519942698dc90a3951306b934bAdam Powell Log.e(TAG, "Error setting local stream volume", e); 19188e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 19198e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } else { 192069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown sStatic.requestUpdateVolume(this, direction); 19218e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 19228e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 19238e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 19248e37a85bf3dc39519942698dc90a3951306b934bAdam Powell /** 19251357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @return the maximum volume at which the playback associated with this route is performed 19261357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @see UserRouteInfo#setVolumeMax(int) 19271357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 19281357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public int getVolumeMax() { 19291357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi if (mPlaybackType == PLAYBACK_TYPE_LOCAL) { 19301357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi int volMax = 0; 19311357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi try { 19321357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi volMax = sStatic.mAudioService.getStreamMaxVolume(mPlaybackStream); 19331357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } catch (RemoteException e) { 19341357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi Log.e(TAG, "Error getting local stream volume", e); 19351357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 19361357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi return volMax; 19371357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } else { 19381357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi return mVolumeMax; 19391357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 19401357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 19411357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 19421357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 19431357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @return how volume is handling on the route 19441357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @see UserRouteInfo#setVolumeHandling(int) 19451357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 19467c090d54e2c0eb5309d3f7dc131e137d9c986793Insun Kang @PlaybackVolume 19471357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public int getVolumeHandling() { 19481357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi return mVolumeHandling; 19491357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 19501357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 1951705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell /** 195292130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * Gets the {@link Display} that should be used by the application to show 195392130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * a {@link android.app.Presentation} on an external display when this route is selected. 195492130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * Depending on the route, this may only be valid if the route is currently 195592130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * selected. 195692130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * <p> 195792130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * The preferred presentation display may change independently of the route 195892130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * being selected or unselected. For example, the presentation display 195992130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * of the default system route may change when an external HDMI display is connected 196092130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * or disconnected even though the route itself has not changed. 196192130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * </p><p> 196292130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * This method may return null if there is no external display associated with 196392130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * the route or if the display is not ready to show UI yet. 196492130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * </p><p> 196592130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * The application should listen for changes to the presentation display 196692130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * using the {@link Callback#onRoutePresentationDisplayChanged} callback and 196792130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * show or dismiss its {@link android.app.Presentation} accordingly when the display 196892130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * becomes available or is removed. 196992130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * </p><p> 197092130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * This method only makes sense for {@link #ROUTE_TYPE_LIVE_VIDEO live video} routes. 197192130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * </p> 197292130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * 197392130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * @return The preferred presentation display to use when this route is 197492130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * selected or null if none. 197592130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * 197692130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * @see #ROUTE_TYPE_LIVE_VIDEO 197792130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * @see android.app.Presentation 197892130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown */ 197992130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown public Display getPresentationDisplay() { 198092130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown return mPresentationDisplay; 198192130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown } 198292130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown 19835830b0b33618940d65197cec99d697b21908fec8Chong Zhang boolean updatePresentationDisplay() { 19845830b0b33618940d65197cec99d697b21908fec8Chong Zhang Display display = choosePresentationDisplay(); 19855830b0b33618940d65197cec99d697b21908fec8Chong Zhang if (mPresentationDisplay != display) { 19865830b0b33618940d65197cec99d697b21908fec8Chong Zhang mPresentationDisplay = display; 19875830b0b33618940d65197cec99d697b21908fec8Chong Zhang return true; 19885830b0b33618940d65197cec99d697b21908fec8Chong Zhang } 19895830b0b33618940d65197cec99d697b21908fec8Chong Zhang return false; 19905830b0b33618940d65197cec99d697b21908fec8Chong Zhang } 19915830b0b33618940d65197cec99d697b21908fec8Chong Zhang 19925830b0b33618940d65197cec99d697b21908fec8Chong Zhang private Display choosePresentationDisplay() { 19935830b0b33618940d65197cec99d697b21908fec8Chong Zhang if ((mSupportedTypes & ROUTE_TYPE_LIVE_VIDEO) != 0) { 19945830b0b33618940d65197cec99d697b21908fec8Chong Zhang Display[] displays = sStatic.getAllPresentationDisplays(); 19955830b0b33618940d65197cec99d697b21908fec8Chong Zhang 19965830b0b33618940d65197cec99d697b21908fec8Chong Zhang // Ensure that the specified display is valid for presentations. 19975830b0b33618940d65197cec99d697b21908fec8Chong Zhang // This check will normally disallow the default display unless it was 19985830b0b33618940d65197cec99d697b21908fec8Chong Zhang // configured as a presentation display for some reason. 19995830b0b33618940d65197cec99d697b21908fec8Chong Zhang if (mPresentationDisplayId >= 0) { 20005830b0b33618940d65197cec99d697b21908fec8Chong Zhang for (Display display : displays) { 20015830b0b33618940d65197cec99d697b21908fec8Chong Zhang if (display.getDisplayId() == mPresentationDisplayId) { 20025830b0b33618940d65197cec99d697b21908fec8Chong Zhang return display; 20035830b0b33618940d65197cec99d697b21908fec8Chong Zhang } 20045830b0b33618940d65197cec99d697b21908fec8Chong Zhang } 20055830b0b33618940d65197cec99d697b21908fec8Chong Zhang return null; 20065830b0b33618940d65197cec99d697b21908fec8Chong Zhang } 20075830b0b33618940d65197cec99d697b21908fec8Chong Zhang 20085830b0b33618940d65197cec99d697b21908fec8Chong Zhang // Find the indicated Wifi display by its address. 20095830b0b33618940d65197cec99d697b21908fec8Chong Zhang if (mDeviceAddress != null) { 20105830b0b33618940d65197cec99d697b21908fec8Chong Zhang for (Display display : displays) { 20115830b0b33618940d65197cec99d697b21908fec8Chong Zhang if (display.getType() == Display.TYPE_WIFI 20125830b0b33618940d65197cec99d697b21908fec8Chong Zhang && mDeviceAddress.equals(display.getAddress())) { 20135830b0b33618940d65197cec99d697b21908fec8Chong Zhang return display; 20145830b0b33618940d65197cec99d697b21908fec8Chong Zhang } 20155830b0b33618940d65197cec99d697b21908fec8Chong Zhang } 20165830b0b33618940d65197cec99d697b21908fec8Chong Zhang return null; 20175830b0b33618940d65197cec99d697b21908fec8Chong Zhang } 20185830b0b33618940d65197cec99d697b21908fec8Chong Zhang 20195830b0b33618940d65197cec99d697b21908fec8Chong Zhang // For the default route, choose the first presentation display from the list. 20205830b0b33618940d65197cec99d697b21908fec8Chong Zhang if (this == sStatic.mDefaultAudioVideo && displays.length > 0) { 20215830b0b33618940d65197cec99d697b21908fec8Chong Zhang return displays[0]; 20225830b0b33618940d65197cec99d697b21908fec8Chong Zhang } 20235830b0b33618940d65197cec99d697b21908fec8Chong Zhang } 20245830b0b33618940d65197cec99d697b21908fec8Chong Zhang return null; 20255830b0b33618940d65197cec99d697b21908fec8Chong Zhang } 20265830b0b33618940d65197cec99d697b21908fec8Chong Zhang 202775af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown /** @hide */ 202875af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown public String getDeviceAddress() { 202975af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown return mDeviceAddress; 203075af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown } 203175af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown 203292130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown /** 2033a27b8fb4296c1271ddf5916843ddffda6764e65fJeff Brown * Returns true if this route is enabled and may be selected. 2034a27b8fb4296c1271ddf5916843ddffda6764e65fJeff Brown * 2035a27b8fb4296c1271ddf5916843ddffda6764e65fJeff Brown * @return True if this route is enabled. 2036705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell */ 2037705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell public boolean isEnabled() { 2038705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell return mEnabled; 2039705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 2040705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 2041a27b8fb4296c1271ddf5916843ddffda6764e65fJeff Brown /** 2042a27b8fb4296c1271ddf5916843ddffda6764e65fJeff Brown * Returns true if the route is in the process of connecting and is not 2043a27b8fb4296c1271ddf5916843ddffda6764e65fJeff Brown * yet ready for use. 2044a27b8fb4296c1271ddf5916843ddffda6764e65fJeff Brown * 2045a27b8fb4296c1271ddf5916843ddffda6764e65fJeff Brown * @return True if this route is in the process of connecting. 2046a27b8fb4296c1271ddf5916843ddffda6764e65fJeff Brown */ 2047a27b8fb4296c1271ddf5916843ddffda6764e65fJeff Brown public boolean isConnecting() { 204839ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown return mResolvedStatusCode == STATUS_CONNECTING; 20490abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown } 20500abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown 20510abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown /** @hide */ 20520abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown public boolean isSelected() { 20530abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown return this == sStatic.mSelectedRoute; 20540abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown } 20550abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown 20560abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown /** @hide */ 20570abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown public boolean isDefault() { 20580abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown return this == sStatic.mDefaultAudioVideo; 20590abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown } 20600abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown 20610abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown /** @hide */ 206259579ce59d6e2c42e6ea1b389ba7e228aaa9122fSungsoo Lim public boolean isBluetooth() { 206359579ce59d6e2c42e6ea1b389ba7e228aaa9122fSungsoo Lim return this == sStatic.mBluetoothA2dpRoute; 206459579ce59d6e2c42e6ea1b389ba7e228aaa9122fSungsoo Lim } 206559579ce59d6e2c42e6ea1b389ba7e228aaa9122fSungsoo Lim 206659579ce59d6e2c42e6ea1b389ba7e228aaa9122fSungsoo Lim /** @hide */ 20670abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown public void select() { 20680abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown selectRouteStatic(mSupportedTypes, this, true); 2069a27b8fb4296c1271ddf5916843ddffda6764e65fJeff Brown } 2070a27b8fb4296c1271ddf5916843ddffda6764e65fJeff Brown 20719a1de308cea2d160778fd977825f10a07b49d738Adam Powell void setStatusInt(CharSequence status) { 20729a1de308cea2d160778fd977825f10a07b49d738Adam Powell if (!status.equals(mStatus)) { 20739a1de308cea2d160778fd977825f10a07b49d738Adam Powell mStatus = status; 20749a1de308cea2d160778fd977825f10a07b49d738Adam Powell if (mGroup != null) { 20759a1de308cea2d160778fd977825f10a07b49d738Adam Powell mGroup.memberStatusChanged(this, status); 20769a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 20779a1de308cea2d160778fd977825f10a07b49d738Adam Powell routeUpdated(); 20789a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 20799a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 20809a1de308cea2d160778fd977825f10a07b49d738Adam Powell 20811357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi final IRemoteVolumeObserver.Stub mRemoteVolObserver = new IRemoteVolumeObserver.Stub() { 208269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown @Override 20831357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public void dispatchRemoteVolumeUpdate(final int direction, final int value) { 20841357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi sStatic.mHandler.post(new Runnable() { 20851357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi @Override 20861357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public void run() { 20871357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi if (mVcb != null) { 20881357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi if (direction != 0) { 20891357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi mVcb.vcb.onVolumeUpdateRequest(mVcb.route, direction); 20901357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } else { 20911357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi mVcb.vcb.onVolumeSetRequest(mVcb.route, value); 20921357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 20931357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 20941357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 20951357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi }); 20961357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 20971357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi }; 20981357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 20999a1de308cea2d160778fd977825f10a07b49d738Adam Powell void routeUpdated() { 21009a1de308cea2d160778fd977825f10a07b49d738Adam Powell updateRoute(this); 21019a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 21029a1de308cea2d160778fd977825f10a07b49d738Adam Powell 21039a1de308cea2d160778fd977825f10a07b49d738Adam Powell @Override 21049a1de308cea2d160778fd977825f10a07b49d738Adam Powell public String toString() { 2105d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell String supportedTypes = typesToString(getSupportedTypes()); 210692130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown return getClass().getSimpleName() + "{ name=" + getName() + 210756d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown ", description=" + getDescription() + 210892130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown ", status=" + getStatus() + 210992130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown ", category=" + getCategory() + 211092130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown ", supportedTypes=" + supportedTypes + 211169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown ", presentationDisplay=" + mPresentationDisplay + " }"; 21129a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 21139a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 21149a1de308cea2d160778fd977825f10a07b49d738Adam Powell 21159a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 21169a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Information about a route that the application may define and modify. 21178e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * A user route defaults to {@link RouteInfo#PLAYBACK_TYPE_REMOTE} and 21188e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * {@link RouteInfo#PLAYBACK_VOLUME_FIXED}. 21199a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 21209a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @see MediaRouter.RouteInfo 21219a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 2122b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn public static class UserRouteInfo extends RouteInfo { 2123ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell RemoteControlClient mRcc; 21245d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik SessionVolumeProvider mSvp; 21259a1de308cea2d160778fd977825f10a07b49d738Adam Powell 21269a1de308cea2d160778fd977825f10a07b49d738Adam Powell UserRouteInfo(RouteCategory category) { 21279a1de308cea2d160778fd977825f10a07b49d738Adam Powell super(category); 21289a1de308cea2d160778fd977825f10a07b49d738Adam Powell mSupportedTypes = ROUTE_TYPE_USER; 21298e37a85bf3dc39519942698dc90a3951306b934bAdam Powell mPlaybackType = PLAYBACK_TYPE_REMOTE; 21308e37a85bf3dc39519942698dc90a3951306b934bAdam Powell mVolumeHandling = PLAYBACK_VOLUME_FIXED; 21319a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 21329a1de308cea2d160778fd977825f10a07b49d738Adam Powell 21339a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 21349a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Set the user-visible name of this route. 21359a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param name Name to display to the user to describe this route 21369a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 21379a1de308cea2d160778fd977825f10a07b49d738Adam Powell public void setName(CharSequence name) { 2138eadd6d2329972129c96dee390a8b786b37313d17Hyundo Moon mNameResId = 0; 21399a1de308cea2d160778fd977825f10a07b49d738Adam Powell mName = name; 21409a1de308cea2d160778fd977825f10a07b49d738Adam Powell routeUpdated(); 21419a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 21425d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik 21430d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell /** 21440d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * Set the user-visible name of this route. 214556d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * <p> 214656d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * The route name identifies the destination represented by the route. 214756d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * It may be a user-supplied name, an alias, or device serial number. 214856d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * </p> 214956d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * 21500d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * @param resId Resource ID of the name to display to the user to describe this route 21510d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell */ 21520d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public void setName(int resId) { 21530d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell mNameResId = resId; 21540d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell mName = null; 21550d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell routeUpdated(); 21560d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell } 21579a1de308cea2d160778fd977825f10a07b49d738Adam Powell 21589a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 215956d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * Set the user-visible description of this route. 216056d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * <p> 216156d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * The route description describes the kind of destination represented by the route. 216256d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * It may be a user-supplied string, a model number or brand of device. 216356d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * </p> 216456d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * 216556d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * @param description The description of the route, or null if none. 216656d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown */ 216756d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown public void setDescription(CharSequence description) { 216856d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown mDescription = description; 216956d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown routeUpdated(); 217056d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown } 217156d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown 217256d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown /** 21739a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Set the current user-visible status for this route. 21749a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param status Status to display to the user to describe what the endpoint 21759a1de308cea2d160778fd977825f10a07b49d738Adam Powell * of this route is currently doing 21769a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 21779a1de308cea2d160778fd977825f10a07b49d738Adam Powell public void setStatus(CharSequence status) { 21789a1de308cea2d160778fd977825f10a07b49d738Adam Powell setStatusInt(status); 21799a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 2180ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell 2181ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell /** 2182ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * Set the RemoteControlClient responsible for reporting playback info for this 2183ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * user route. 2184ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * 2185ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * <p>If this route manages remote playback, the data exposed by this 2186ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * RemoteControlClient will be used to reflect and update information 2187ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * such as route volume info in related UIs.</p> 2188ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * 21891357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * <p>The RemoteControlClient must have been previously registered with 21901357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * {@link AudioManager#registerRemoteControlClient(RemoteControlClient)}.</p> 21911357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * 2192ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * @param rcc RemoteControlClient associated with this route 2193ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell */ 2194ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell public void setRemoteControlClient(RemoteControlClient rcc) { 2195ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell mRcc = rcc; 21961357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi updatePlaybackInfoOnRcc(); 2197ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell } 2198ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell 2199ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell /** 22004599696591f745b3a546197d2ba7e5cfc5562484Adam Powell * Retrieve the RemoteControlClient associated with this route, if one has been set. 22014599696591f745b3a546197d2ba7e5cfc5562484Adam Powell * 22024599696591f745b3a546197d2ba7e5cfc5562484Adam Powell * @return the RemoteControlClient associated with this route 22034599696591f745b3a546197d2ba7e5cfc5562484Adam Powell * @see #setRemoteControlClient(RemoteControlClient) 22044599696591f745b3a546197d2ba7e5cfc5562484Adam Powell */ 22054599696591f745b3a546197d2ba7e5cfc5562484Adam Powell public RemoteControlClient getRemoteControlClient() { 22064599696591f745b3a546197d2ba7e5cfc5562484Adam Powell return mRcc; 22074599696591f745b3a546197d2ba7e5cfc5562484Adam Powell } 22084599696591f745b3a546197d2ba7e5cfc5562484Adam Powell 22094599696591f745b3a546197d2ba7e5cfc5562484Adam Powell /** 2210ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * Set an icon that will be used to represent this route. 2211ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * The system may use this icon in picker UIs or similar. 2212ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * 2213ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * @param icon icon drawable to use to represent this route 2214ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell */ 2215ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell public void setIconDrawable(Drawable icon) { 2216ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell mIcon = icon; 2217ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell } 2218ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell 2219ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell /** 2220ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * Set an icon that will be used to represent this route. 2221ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * The system may use this icon in picker UIs or similar. 2222ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * 222371c69897ad0a55d590698bfa399bfe99c763b9dbAdam Powell * @param resId Resource ID of an icon drawable to use to represent this route 2224ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell */ 22257b9c912f536925ac6ec43935d6e97506851b33d6Tor Norbye public void setIconResource(@DrawableRes int resId) { 2226ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell setIconDrawable(sStatic.mResources.getDrawable(resId)); 2227ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell } 22281357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 22291357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 22301357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * Set a callback to be notified of volume update requests 22311357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @param vcb 22321357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 22331357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public void setVolumeCallback(VolumeCallback vcb) { 22341357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi mVcb = new VolumeCallbackInfo(vcb, this); 22351357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 22361357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 22371357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 22381357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * Defines whether playback associated with this route is "local" 22391357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * ({@link RouteInfo#PLAYBACK_TYPE_LOCAL}) or "remote" 22401357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * ({@link RouteInfo#PLAYBACK_TYPE_REMOTE}). 22411357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @param type 22421357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 22437c090d54e2c0eb5309d3f7dc131e137d9c986793Insun Kang public void setPlaybackType(@RouteInfo.PlaybackType int type) { 22441357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi if (mPlaybackType != type) { 22451357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi mPlaybackType = type; 2246430fc48865e5a371b08f180390946b96d73848feRoboErik configureSessionVolume(); 22471357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 22481357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 22491357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 22501357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 22511357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * Defines whether volume for the playback associated with this route is fixed 22521357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * ({@link RouteInfo#PLAYBACK_VOLUME_FIXED}) or can modified 22531357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * ({@link RouteInfo#PLAYBACK_VOLUME_VARIABLE}). 22541357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @param volumeHandling 22551357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 22567c090d54e2c0eb5309d3f7dc131e137d9c986793Insun Kang public void setVolumeHandling(@RouteInfo.PlaybackVolume int volumeHandling) { 22571357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi if (mVolumeHandling != volumeHandling) { 22581357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi mVolumeHandling = volumeHandling; 2259430fc48865e5a371b08f180390946b96d73848feRoboErik configureSessionVolume(); 22601357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 22611357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 22621357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 22631357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 22641357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * Defines at what volume the playback associated with this route is performed (for user 22651357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * feedback purposes). This information is only used when the playback is not local. 22661357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @param volume 22671357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 22681357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public void setVolume(int volume) { 22698e37a85bf3dc39519942698dc90a3951306b934bAdam Powell volume = Math.max(0, Math.min(volume, getVolumeMax())); 22701357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi if (mVolume != volume) { 22711357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi mVolume = volume; 2272430fc48865e5a371b08f180390946b96d73848feRoboErik if (mSvp != null) { 22730d0f67f5ee5f939a1b611bc4583212707afd9beeRoboErik mSvp.setCurrentVolume(mVolume); 22745d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik } 22758e37a85bf3dc39519942698dc90a3951306b934bAdam Powell dispatchRouteVolumeChanged(this); 2276f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell if (mGroup != null) { 2277f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell mGroup.memberVolumeChanged(this); 2278f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell } 22798e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 22808e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 22818e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 22828e37a85bf3dc39519942698dc90a3951306b934bAdam Powell @Override 22838e37a85bf3dc39519942698dc90a3951306b934bAdam Powell public void requestSetVolume(int volume) { 22848e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (mVolumeHandling == PLAYBACK_VOLUME_VARIABLE) { 22858e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (mVcb == null) { 22868e37a85bf3dc39519942698dc90a3951306b934bAdam Powell Log.e(TAG, "Cannot requestSetVolume on user route - no volume callback set"); 22878e37a85bf3dc39519942698dc90a3951306b934bAdam Powell return; 22888e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 22898e37a85bf3dc39519942698dc90a3951306b934bAdam Powell mVcb.vcb.onVolumeSetRequest(this, volume); 22908e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 22918e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 22928e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 22938e37a85bf3dc39519942698dc90a3951306b934bAdam Powell @Override 22948e37a85bf3dc39519942698dc90a3951306b934bAdam Powell public void requestUpdateVolume(int direction) { 22958e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (mVolumeHandling == PLAYBACK_VOLUME_VARIABLE) { 22968e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (mVcb == null) { 22978e37a85bf3dc39519942698dc90a3951306b934bAdam Powell Log.e(TAG, "Cannot requestChangeVolume on user route - no volumec callback set"); 22988e37a85bf3dc39519942698dc90a3951306b934bAdam Powell return; 22998e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 23008e37a85bf3dc39519942698dc90a3951306b934bAdam Powell mVcb.vcb.onVolumeUpdateRequest(this, direction); 23011357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 23021357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 23031357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 23041357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 23051357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * Defines the maximum volume at which the playback associated with this route is performed 23061357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * (for user feedback purposes). This information is only used when the playback is not 23071357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * local. 23081357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @param volumeMax 23091357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 23101357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public void setVolumeMax(int volumeMax) { 23111357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi if (mVolumeMax != volumeMax) { 23121357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi mVolumeMax = volumeMax; 2313430fc48865e5a371b08f180390946b96d73848feRoboErik configureSessionVolume(); 23141357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 23151357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 23161357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 23171357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 23181357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * Defines over what stream type the media is presented. 23191357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @param stream 23201357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 23211357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public void setPlaybackStream(int stream) { 23221357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi if (mPlaybackStream != stream) { 23231357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi mPlaybackStream = stream; 2324430fc48865e5a371b08f180390946b96d73848feRoboErik configureSessionVolume(); 23251357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 23261357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 23271357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 23281357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi private void updatePlaybackInfoOnRcc() { 2329430fc48865e5a371b08f180390946b96d73848feRoboErik configureSessionVolume(); 23305d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik } 23315d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik 23325d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik private void configureSessionVolume() { 23335d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik if (mRcc == null) { 23345d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik if (DEBUG) { 2335eadd6d2329972129c96dee390a8b786b37313d17Hyundo Moon Log.d(TAG, "No Rcc to configure volume for route " + getName()); 23365d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik } 23375d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik return; 23385d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik } 23395d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik MediaSession session = mRcc.getMediaSession(); 23405d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik if (session == null) { 23415d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik if (DEBUG) { 23425d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik Log.d(TAG, "Rcc has no session to configure volume"); 23435d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik } 23445d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik return; 23455d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik } 23465d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik if (mPlaybackType == RemoteControlClient.PLAYBACK_TYPE_REMOTE) { 23477c090d54e2c0eb5309d3f7dc131e137d9c986793Insun Kang @VolumeProvider.ControlType int volumeControl = 23487c090d54e2c0eb5309d3f7dc131e137d9c986793Insun Kang VolumeProvider.VOLUME_CONTROL_FIXED; 23495d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik switch (mVolumeHandling) { 23505d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik case RemoteControlClient.PLAYBACK_VOLUME_VARIABLE: 2351ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik volumeControl = VolumeProvider.VOLUME_CONTROL_ABSOLUTE; 23525d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik break; 23535d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik case RemoteControlClient.PLAYBACK_VOLUME_FIXED: 23545d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik default: 23555d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik break; 23561357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 23575d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik // Only register a new listener if necessary 23585d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik if (mSvp == null || mSvp.getVolumeControl() != volumeControl 23595d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik || mSvp.getMaxVolume() != mVolumeMax) { 23600d0f67f5ee5f939a1b611bc4583212707afd9beeRoboErik mSvp = new SessionVolumeProvider(volumeControl, mVolumeMax, mVolume); 23615d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik session.setPlaybackToRemote(mSvp); 23625d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik } 23635d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik } else { 23645d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik // We only know how to handle local and remote, fall back to local if not remote. 23659db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik AudioAttributes.Builder bob = new AudioAttributes.Builder(); 23669db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik bob.setLegacyStreamType(mPlaybackStream); 23679db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik session.setPlaybackToLocal(bob.build()); 23685d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik mSvp = null; 23691357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 23701357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 23711357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 2372ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik class SessionVolumeProvider extends VolumeProvider { 23735d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik 23747c090d54e2c0eb5309d3f7dc131e137d9c986793Insun Kang public SessionVolumeProvider(@VolumeProvider.ControlType int volumeControl, 23757c090d54e2c0eb5309d3f7dc131e137d9c986793Insun Kang int maxVolume, int currentVolume) { 23760d0f67f5ee5f939a1b611bc4583212707afd9beeRoboErik super(volumeControl, maxVolume, currentVolume); 23775d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik } 23785d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik 23795d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik @Override 23805d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik public void onSetVolumeTo(final int volume) { 23815d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik sStatic.mHandler.post(new Runnable() { 23825d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik @Override 23835d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik public void run() { 23845d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik if (mVcb != null) { 23855d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik mVcb.vcb.onVolumeSetRequest(mVcb.route, volume); 23865d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik } 23875d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik } 23885d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik }); 23895d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik } 23905d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik 23915d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik @Override 23921ff5b1648a051e9650614f0c0f1b3f449777db81RoboErik public void onAdjustVolume(final int direction) { 23935d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik sStatic.mHandler.post(new Runnable() { 23945d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik @Override 23955d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik public void run() { 23965d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik if (mVcb != null) { 23971ff5b1648a051e9650614f0c0f1b3f449777db81RoboErik mVcb.vcb.onVolumeUpdateRequest(mVcb.route, direction); 23985d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik } 23995d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik } 24005d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik }); 24015d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik } 24025d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik } 24039a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 24049a1de308cea2d160778fd977825f10a07b49d738Adam Powell 24059a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 24069a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Information about a route that consists of multiple other routes in a group. 24079a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 2408b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn public static class RouteGroup extends RouteInfo { 24099a1de308cea2d160778fd977825f10a07b49d738Adam Powell final ArrayList<RouteInfo> mRoutes = new ArrayList<RouteInfo>(); 24109a1de308cea2d160778fd977825f10a07b49d738Adam Powell private boolean mUpdateName; 24119a1de308cea2d160778fd977825f10a07b49d738Adam Powell 24129a1de308cea2d160778fd977825f10a07b49d738Adam Powell RouteGroup(RouteCategory category) { 24139a1de308cea2d160778fd977825f10a07b49d738Adam Powell super(category); 24149a1de308cea2d160778fd977825f10a07b49d738Adam Powell mGroup = this; 24158e37a85bf3dc39519942698dc90a3951306b934bAdam Powell mVolumeHandling = PLAYBACK_VOLUME_FIXED; 24169a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 24179a1de308cea2d160778fd977825f10a07b49d738Adam Powell 241869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown @Override 24190d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell CharSequence getName(Resources res) { 24209a1de308cea2d160778fd977825f10a07b49d738Adam Powell if (mUpdateName) updateName(); 24210d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell return super.getName(res); 24229a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 24239a1de308cea2d160778fd977825f10a07b49d738Adam Powell 24249a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 24259a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Add a route to this group. The route must not currently belong to another group. 24269a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 24279a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param route route to add to this group 24289a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 24299a1de308cea2d160778fd977825f10a07b49d738Adam Powell public void addRoute(RouteInfo route) { 24309a1de308cea2d160778fd977825f10a07b49d738Adam Powell if (route.getGroup() != null) { 24319a1de308cea2d160778fd977825f10a07b49d738Adam Powell throw new IllegalStateException("Route " + route + " is already part of a group."); 24329a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 24339a1de308cea2d160778fd977825f10a07b49d738Adam Powell if (route.getCategory() != mCategory) { 24349a1de308cea2d160778fd977825f10a07b49d738Adam Powell throw new IllegalArgumentException( 24359a1de308cea2d160778fd977825f10a07b49d738Adam Powell "Route cannot be added to a group with a different category. " + 24369a1de308cea2d160778fd977825f10a07b49d738Adam Powell "(Route category=" + route.getCategory() + 24379a1de308cea2d160778fd977825f10a07b49d738Adam Powell " group category=" + mCategory + ")"); 24389a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 2439d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell final int at = mRoutes.size(); 24409a1de308cea2d160778fd977825f10a07b49d738Adam Powell mRoutes.add(route); 2441d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell route.mGroup = this; 24429a1de308cea2d160778fd977825f10a07b49d738Adam Powell mUpdateName = true; 2443f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell updateVolume(); 24449a1de308cea2d160778fd977825f10a07b49d738Adam Powell routeUpdated(); 2445f3b653a21cdffe04c94c275e69ecb56e00766e82Adam Powell dispatchRouteGrouped(route, this, at); 24469a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 24479a1de308cea2d160778fd977825f10a07b49d738Adam Powell 24489a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 24499a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Add a route to this group before the specified index. 24509a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 24519a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param route route to add 24529a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param insertAt insert the new route before this index 24539a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 24549a1de308cea2d160778fd977825f10a07b49d738Adam Powell public void addRoute(RouteInfo route, int insertAt) { 24559a1de308cea2d160778fd977825f10a07b49d738Adam Powell if (route.getGroup() != null) { 24569a1de308cea2d160778fd977825f10a07b49d738Adam Powell throw new IllegalStateException("Route " + route + " is already part of a group."); 24579a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 24589a1de308cea2d160778fd977825f10a07b49d738Adam Powell if (route.getCategory() != mCategory) { 24599a1de308cea2d160778fd977825f10a07b49d738Adam Powell throw new IllegalArgumentException( 24609a1de308cea2d160778fd977825f10a07b49d738Adam Powell "Route cannot be added to a group with a different category. " + 24619a1de308cea2d160778fd977825f10a07b49d738Adam Powell "(Route category=" + route.getCategory() + 24629a1de308cea2d160778fd977825f10a07b49d738Adam Powell " group category=" + mCategory + ")"); 24639a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 24649a1de308cea2d160778fd977825f10a07b49d738Adam Powell mRoutes.add(insertAt, route); 2465d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell route.mGroup = this; 24669a1de308cea2d160778fd977825f10a07b49d738Adam Powell mUpdateName = true; 2467f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell updateVolume(); 24689a1de308cea2d160778fd977825f10a07b49d738Adam Powell routeUpdated(); 2469f3b653a21cdffe04c94c275e69ecb56e00766e82Adam Powell dispatchRouteGrouped(route, this, insertAt); 24709a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 24719a1de308cea2d160778fd977825f10a07b49d738Adam Powell 24729a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 24739a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Remove a route from this group. 24749a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 24759a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param route route to remove 24769a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 24779a1de308cea2d160778fd977825f10a07b49d738Adam Powell public void removeRoute(RouteInfo route) { 24789a1de308cea2d160778fd977825f10a07b49d738Adam Powell if (route.getGroup() != this) { 24799a1de308cea2d160778fd977825f10a07b49d738Adam Powell throw new IllegalArgumentException("Route " + route + 24809a1de308cea2d160778fd977825f10a07b49d738Adam Powell " is not a member of this group."); 24819a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 24829a1de308cea2d160778fd977825f10a07b49d738Adam Powell mRoutes.remove(route); 2483d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell route.mGroup = null; 24849a1de308cea2d160778fd977825f10a07b49d738Adam Powell mUpdateName = true; 2485f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell updateVolume(); 2486d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell dispatchRouteUngrouped(route, this); 24879a1de308cea2d160778fd977825f10a07b49d738Adam Powell routeUpdated(); 24889a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 24899a1de308cea2d160778fd977825f10a07b49d738Adam Powell 24909a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 24919a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Remove the route at the specified index from this group. 24929a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 24939a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param index index of the route to remove 24949a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 24959a1de308cea2d160778fd977825f10a07b49d738Adam Powell public void removeRoute(int index) { 2496d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell RouteInfo route = mRoutes.remove(index); 2497d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell route.mGroup = null; 24989a1de308cea2d160778fd977825f10a07b49d738Adam Powell mUpdateName = true; 2499f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell updateVolume(); 2500d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell dispatchRouteUngrouped(route, this); 25019a1de308cea2d160778fd977825f10a07b49d738Adam Powell routeUpdated(); 25029a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 25039a1de308cea2d160778fd977825f10a07b49d738Adam Powell 2504d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell /** 2505d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @return The number of routes in this group 2506d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell */ 2507d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell public int getRouteCount() { 2508d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell return mRoutes.size(); 2509d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell } 2510d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell 2511d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell /** 2512d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * Return the route in this group at the specified index 2513d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * 2514d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param index Index to fetch 2515d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @return The route at index 2516d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell */ 2517d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell public RouteInfo getRouteAt(int index) { 2518d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell return mRoutes.get(index); 2519d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell } 2520d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell 2521ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell /** 2522ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * Set an icon that will be used to represent this group. 2523ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * The system may use this icon in picker UIs or similar. 2524ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * 2525ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * @param icon icon drawable to use to represent this group 2526ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell */ 2527ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell public void setIconDrawable(Drawable icon) { 2528ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell mIcon = icon; 2529ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell } 2530ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell 2531ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell /** 2532ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * Set an icon that will be used to represent this group. 2533ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * The system may use this icon in picker UIs or similar. 2534ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * 253571c69897ad0a55d590698bfa399bfe99c763b9dbAdam Powell * @param resId Resource ID of an icon drawable to use to represent this group 2536ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell */ 25377b9c912f536925ac6ec43935d6e97506851b33d6Tor Norbye public void setIconResource(@DrawableRes int resId) { 2538ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell setIconDrawable(sStatic.mResources.getDrawable(resId)); 2539ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell } 2540ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell 25418e37a85bf3dc39519942698dc90a3951306b934bAdam Powell @Override 25428e37a85bf3dc39519942698dc90a3951306b934bAdam Powell public void requestSetVolume(int volume) { 25438e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final int maxVol = getVolumeMax(); 25448e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (maxVol == 0) { 25458e37a85bf3dc39519942698dc90a3951306b934bAdam Powell return; 25468e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 25478e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 25488e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final float scaledVolume = (float) volume / maxVol; 25498e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final int routeCount = getRouteCount(); 25508e37a85bf3dc39519942698dc90a3951306b934bAdam Powell for (int i = 0; i < routeCount; i++) { 25518e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final RouteInfo route = getRouteAt(i); 25528e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final int routeVol = (int) (scaledVolume * route.getVolumeMax()); 25538e37a85bf3dc39519942698dc90a3951306b934bAdam Powell route.requestSetVolume(routeVol); 25548e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 25558e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (volume != mVolume) { 25568e37a85bf3dc39519942698dc90a3951306b934bAdam Powell mVolume = volume; 25578e37a85bf3dc39519942698dc90a3951306b934bAdam Powell dispatchRouteVolumeChanged(this); 25588e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 25598e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 25608e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 25618e37a85bf3dc39519942698dc90a3951306b934bAdam Powell @Override 25628e37a85bf3dc39519942698dc90a3951306b934bAdam Powell public void requestUpdateVolume(int direction) { 25638e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final int maxVol = getVolumeMax(); 25648e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (maxVol == 0) { 25658e37a85bf3dc39519942698dc90a3951306b934bAdam Powell return; 25668e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 25678e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 25688e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final int routeCount = getRouteCount(); 2569f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell int volume = 0; 25708e37a85bf3dc39519942698dc90a3951306b934bAdam Powell for (int i = 0; i < routeCount; i++) { 25718e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final RouteInfo route = getRouteAt(i); 25728e37a85bf3dc39519942698dc90a3951306b934bAdam Powell route.requestUpdateVolume(direction); 2573f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell final int routeVol = route.getVolume(); 2574f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell if (routeVol > volume) { 2575f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell volume = routeVol; 2576f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell } 25778e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 25788e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (volume != mVolume) { 25798e37a85bf3dc39519942698dc90a3951306b934bAdam Powell mVolume = volume; 25808e37a85bf3dc39519942698dc90a3951306b934bAdam Powell dispatchRouteVolumeChanged(this); 25818e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 25828e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 25838e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 25849a1de308cea2d160778fd977825f10a07b49d738Adam Powell void memberNameChanged(RouteInfo info, CharSequence name) { 25859a1de308cea2d160778fd977825f10a07b49d738Adam Powell mUpdateName = true; 25869a1de308cea2d160778fd977825f10a07b49d738Adam Powell routeUpdated(); 25879a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 25889a1de308cea2d160778fd977825f10a07b49d738Adam Powell 25899a1de308cea2d160778fd977825f10a07b49d738Adam Powell void memberStatusChanged(RouteInfo info, CharSequence status) { 25909a1de308cea2d160778fd977825f10a07b49d738Adam Powell setStatusInt(status); 25919a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 25929a1de308cea2d160778fd977825f10a07b49d738Adam Powell 2593f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell void memberVolumeChanged(RouteInfo info) { 2594f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell updateVolume(); 2595f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell } 2596f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell 2597f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell void updateVolume() { 2598f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell // A group always represents the highest component volume value. 2599f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell final int routeCount = getRouteCount(); 2600f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell int volume = 0; 2601f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell for (int i = 0; i < routeCount; i++) { 2602f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell final int routeVol = getRouteAt(i).getVolume(); 2603f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell if (routeVol > volume) { 2604f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell volume = routeVol; 2605f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell } 2606f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell } 2607f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell if (volume != mVolume) { 2608f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell mVolume = volume; 2609f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell dispatchRouteVolumeChanged(this); 2610f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell } 2611f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell } 2612f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell 2613d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell @Override 2614d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell void routeUpdated() { 2615d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell int types = 0; 2616d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell final int count = mRoutes.size(); 2617b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell if (count == 0) { 2618b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell // Don't keep empty groups in the router. 261969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown MediaRouter.removeRouteStatic(this); 2620b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell return; 2621b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell } 2622b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell 26238e37a85bf3dc39519942698dc90a3951306b934bAdam Powell int maxVolume = 0; 26248e37a85bf3dc39519942698dc90a3951306b934bAdam Powell boolean isLocal = true; 26258e37a85bf3dc39519942698dc90a3951306b934bAdam Powell boolean isFixedVolume = true; 2626d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell for (int i = 0; i < count; i++) { 26278e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final RouteInfo route = mRoutes.get(i); 26288e37a85bf3dc39519942698dc90a3951306b934bAdam Powell types |= route.mSupportedTypes; 26298e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final int routeMaxVolume = route.getVolumeMax(); 26308e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (routeMaxVolume > maxVolume) { 26318e37a85bf3dc39519942698dc90a3951306b934bAdam Powell maxVolume = routeMaxVolume; 26328e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 26338e37a85bf3dc39519942698dc90a3951306b934bAdam Powell isLocal &= route.getPlaybackType() == PLAYBACK_TYPE_LOCAL; 26348e37a85bf3dc39519942698dc90a3951306b934bAdam Powell isFixedVolume &= route.getVolumeHandling() == PLAYBACK_VOLUME_FIXED; 2635d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell } 26368e37a85bf3dc39519942698dc90a3951306b934bAdam Powell mPlaybackType = isLocal ? PLAYBACK_TYPE_LOCAL : PLAYBACK_TYPE_REMOTE; 26378e37a85bf3dc39519942698dc90a3951306b934bAdam Powell mVolumeHandling = isFixedVolume ? PLAYBACK_VOLUME_FIXED : PLAYBACK_VOLUME_VARIABLE; 2638d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell mSupportedTypes = types; 26398e37a85bf3dc39519942698dc90a3951306b934bAdam Powell mVolumeMax = maxVolume; 2640d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell mIcon = count == 1 ? mRoutes.get(0).getIconDrawable() : null; 2641d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell super.routeUpdated(); 2642d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell } 2643d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell 26449a1de308cea2d160778fd977825f10a07b49d738Adam Powell void updateName() { 26459a1de308cea2d160778fd977825f10a07b49d738Adam Powell final StringBuilder sb = new StringBuilder(); 26469a1de308cea2d160778fd977825f10a07b49d738Adam Powell final int count = mRoutes.size(); 26479a1de308cea2d160778fd977825f10a07b49d738Adam Powell for (int i = 0; i < count; i++) { 26489a1de308cea2d160778fd977825f10a07b49d738Adam Powell final RouteInfo info = mRoutes.get(i); 2649b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell // TODO: There's probably a much more correct way to localize this. 2650eadd6d2329972129c96dee390a8b786b37313d17Hyundo Moon if (i > 0) { 2651eadd6d2329972129c96dee390a8b786b37313d17Hyundo Moon sb.append(", "); 2652eadd6d2329972129c96dee390a8b786b37313d17Hyundo Moon } 2653eadd6d2329972129c96dee390a8b786b37313d17Hyundo Moon sb.append(info.getName()); 26549a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 26559a1de308cea2d160778fd977825f10a07b49d738Adam Powell mName = sb.toString(); 26569a1de308cea2d160778fd977825f10a07b49d738Adam Powell mUpdateName = false; 26579a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 2658d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell 2659d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell @Override 2660d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell public String toString() { 2661d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell StringBuilder sb = new StringBuilder(super.toString()); 2662d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell sb.append('['); 2663d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell final int count = mRoutes.size(); 2664d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell for (int i = 0; i < count; i++) { 2665d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell if (i > 0) sb.append(", "); 2666d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell sb.append(mRoutes.get(i)); 2667d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell } 2668d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell sb.append(']'); 2669d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell return sb.toString(); 2670d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell } 26719a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 26729a1de308cea2d160778fd977825f10a07b49d738Adam Powell 26739a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 26749a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Definition of a category of routes. All routes belong to a category. 26759a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 2676b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn public static class RouteCategory { 26779a1de308cea2d160778fd977825f10a07b49d738Adam Powell CharSequence mName; 26780d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell int mNameResId; 26799a1de308cea2d160778fd977825f10a07b49d738Adam Powell int mTypes; 26809a1de308cea2d160778fd977825f10a07b49d738Adam Powell final boolean mGroupable; 2681705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell boolean mIsSystem; 26829a1de308cea2d160778fd977825f10a07b49d738Adam Powell 26839a1de308cea2d160778fd977825f10a07b49d738Adam Powell RouteCategory(CharSequence name, int types, boolean groupable) { 26849a1de308cea2d160778fd977825f10a07b49d738Adam Powell mName = name; 26859a1de308cea2d160778fd977825f10a07b49d738Adam Powell mTypes = types; 26869a1de308cea2d160778fd977825f10a07b49d738Adam Powell mGroupable = groupable; 26879a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 26889a1de308cea2d160778fd977825f10a07b49d738Adam Powell 26890d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell RouteCategory(int nameResId, int types, boolean groupable) { 26900d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell mNameResId = nameResId; 26910d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell mTypes = types; 26920d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell mGroupable = groupable; 26930d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell } 26940d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell 26959a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 26969a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @return the name of this route category 26979a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 26989a1de308cea2d160778fd977825f10a07b49d738Adam Powell public CharSequence getName() { 26990d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell return getName(sStatic.mResources); 27000d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell } 27015d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik 27020d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell /** 27030d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * Return the properly localized/configuration dependent name of this RouteCategory. 27045d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik * 27050d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * @param context Context to resolve name resources 27060d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * @return the name of this route category 27070d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell */ 27080d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public CharSequence getName(Context context) { 27090d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell return getName(context.getResources()); 27100d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell } 27115d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik 27120d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell CharSequence getName(Resources res) { 27130d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell if (mNameResId != 0) { 27140d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell return res.getText(mNameResId); 27150d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell } 27169a1de308cea2d160778fd977825f10a07b49d738Adam Powell return mName; 27179a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 27189a1de308cea2d160778fd977825f10a07b49d738Adam Powell 27199a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 2720d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * Return the current list of routes in this category that have been added 2721d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * to the MediaRouter. 27229a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 2723d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * <p>This list will not include routes that are nested within RouteGroups. 2724d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * A RouteGroup is treated as a single route within its category.</p> 2725d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * 2726d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param out a List to fill with the routes in this category. If this parameter is 2727d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * non-null, it will be cleared, filled with the current routes with this 2728d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * category, and returned. If this parameter is null, a new List will be 2729d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * allocated to report the category's current routes. 2730d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @return A list with the routes in this category that have been added to the MediaRouter. 27319a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 2732d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell public List<RouteInfo> getRoutes(List<RouteInfo> out) { 2733d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell if (out == null) { 2734d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell out = new ArrayList<RouteInfo>(); 2735d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell } else { 2736d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell out.clear(); 2737d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell } 2738d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell 2739b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn final int count = getRouteCountStatic(); 2740d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell for (int i = 0; i < count; i++) { 2741b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn final RouteInfo route = getRouteAtStatic(i); 2742d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell if (route.mCategory == this) { 2743d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell out.add(route); 2744d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell } 2745d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell } 2746d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell return out; 27479a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 27489a1de308cea2d160778fd977825f10a07b49d738Adam Powell 27499a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 27509a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @return Flag set describing the route types supported by this category 27519a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 27529a1de308cea2d160778fd977825f10a07b49d738Adam Powell public int getSupportedTypes() { 27539a1de308cea2d160778fd977825f10a07b49d738Adam Powell return mTypes; 27549a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 27559a1de308cea2d160778fd977825f10a07b49d738Adam Powell 27569a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 27579a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Return whether or not this category supports grouping. 27589a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 27599a1de308cea2d160778fd977825f10a07b49d738Adam Powell * <p>If this method returns true, all routes obtained from this category 2760d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * via calls to {@link #getRouteAt(int)} will be {@link MediaRouter.RouteGroup}s.</p> 27619a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 27629a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @return true if this category supports 27639a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 27649a1de308cea2d160778fd977825f10a07b49d738Adam Powell public boolean isGroupable() { 27659a1de308cea2d160778fd977825f10a07b49d738Adam Powell return mGroupable; 27669a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 27679a1de308cea2d160778fd977825f10a07b49d738Adam Powell 2768705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell /** 2769705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell * @return true if this is the category reserved for system routes. 2770705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell * @hide 2771705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell */ 2772705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell public boolean isSystem() { 2773705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell return mIsSystem; 2774705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 2775705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 277669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown @Override 27779a1de308cea2d160778fd977825f10a07b49d738Adam Powell public String toString() { 2778eadd6d2329972129c96dee390a8b786b37313d17Hyundo Moon return "RouteCategory{ name=" + getName() + " types=" + typesToString(mTypes) + 2779d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell " groupable=" + mGroupable + " }"; 27809a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 27819a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 27829a1de308cea2d160778fd977825f10a07b49d738Adam Powell 27839a1de308cea2d160778fd977825f10a07b49d738Adam Powell static class CallbackInfo { 27849a1de308cea2d160778fd977825f10a07b49d738Adam Powell public int type; 278566f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown public int flags; 2786b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn public final Callback cb; 2787b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn public final MediaRouter router; 27889a1de308cea2d160778fd977825f10a07b49d738Adam Powell 278966f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown public CallbackInfo(Callback cb, int type, int flags, MediaRouter router) { 27909a1de308cea2d160778fd977825f10a07b49d738Adam Powell this.cb = cb; 27919a1de308cea2d160778fd977825f10a07b49d738Adam Powell this.type = type; 279266f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown this.flags = flags; 2793b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn this.router = router; 27949a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 279566f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown 279666f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown public boolean filterRouteEvent(RouteInfo route) { 2797af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown return filterRouteEvent(route.mSupportedTypes); 2798af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown } 2799af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown 2800af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown public boolean filterRouteEvent(int supportedTypes) { 280166f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown return (flags & CALLBACK_FLAG_UNFILTERED_EVENTS) != 0 2802af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown || (type & supportedTypes) != 0; 280366f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown } 28049a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 28059a1de308cea2d160778fd977825f10a07b49d738Adam Powell 28069a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 28079a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Interface for receiving events about media routing changes. 28089a1de308cea2d160778fd977825f10a07b49d738Adam Powell * All methods of this interface will be called from the application's main thread. 280966f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * <p> 281066f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * A Callback will only receive events relevant to routes that the callback 281166f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * was registered for unless the {@link MediaRouter#CALLBACK_FLAG_UNFILTERED_EVENTS} 281266f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * flag was specified in {@link MediaRouter#addCallback(int, Callback, int)}. 281366f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * </p> 28149a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 281566f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * @see MediaRouter#addCallback(int, Callback, int) 28169a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @see MediaRouter#removeCallback(Callback) 28179a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 28180d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public static abstract class Callback { 28199a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 28209a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Called when the supplied route becomes selected as the active route 28219a1de308cea2d160778fd977825f10a07b49d738Adam Powell * for the given route type. 28229a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 2823d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param router the MediaRouter reporting the event 28249a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param type Type flag set indicating the routes that have been selected 28259a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param info Route that has been selected for the given route types 28269a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 28270d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public abstract void onRouteSelected(MediaRouter router, int type, RouteInfo info); 28289a1de308cea2d160778fd977825f10a07b49d738Adam Powell 28299a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 28309a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Called when the supplied route becomes unselected as the active route 28319a1de308cea2d160778fd977825f10a07b49d738Adam Powell * for the given route type. 28329a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 2833d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param router the MediaRouter reporting the event 28349a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param type Type flag set indicating the routes that have been unselected 28359a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param info Route that has been unselected for the given route types 28369a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 28370d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public abstract void onRouteUnselected(MediaRouter router, int type, RouteInfo info); 28389a1de308cea2d160778fd977825f10a07b49d738Adam Powell 28399a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 28409a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Called when a route for the specified type was added. 28419a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 2842d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param router the MediaRouter reporting the event 28439a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param info Route that has become available for use 28449a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 28450d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public abstract void onRouteAdded(MediaRouter router, RouteInfo info); 28469a1de308cea2d160778fd977825f10a07b49d738Adam Powell 28479a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 28489a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Called when a route for the specified type was removed. 28499a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 2850d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param router the MediaRouter reporting the event 28519a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param info Route that has been removed from availability 28529a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 28530d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public abstract void onRouteRemoved(MediaRouter router, RouteInfo info); 28549a1de308cea2d160778fd977825f10a07b49d738Adam Powell 28559a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 28569a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Called when an aspect of the indicated route has changed. 28579a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 28589a1de308cea2d160778fd977825f10a07b49d738Adam Powell * <p>This will not indicate that the types supported by this route have 28599a1de308cea2d160778fd977825f10a07b49d738Adam Powell * changed, only that cosmetic info such as name or status have been updated.</p> 28609a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 2861d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param router the MediaRouter reporting the event 28629a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param info The route that was changed 28639a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 28640d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public abstract void onRouteChanged(MediaRouter router, RouteInfo info); 2865d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell 2866d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell /** 2867d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * Called when a route is added to a group. 2868d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * 2869d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param router the MediaRouter reporting the event 2870d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param info The route that was added 2871d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param group The group the route was added to 2872d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param index The route index within group that info was added at 2873d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell */ 28740d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public abstract void onRouteGrouped(MediaRouter router, RouteInfo info, RouteGroup group, 28750d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell int index); 2876d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell 2877d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell /** 2878d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * Called when a route is removed from a group. 2879d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * 2880d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param router the MediaRouter reporting the event 2881d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param info The route that was removed 2882d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param group The group the route was removed from 2883d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell */ 28840d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public abstract void onRouteUngrouped(MediaRouter router, RouteInfo info, RouteGroup group); 28858e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 28868e37a85bf3dc39519942698dc90a3951306b934bAdam Powell /** 28878e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * Called when a route's volume changes. 28888e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * 28898e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * @param router the MediaRouter reporting the event 28908e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * @param info The route with altered volume 28918e37a85bf3dc39519942698dc90a3951306b934bAdam Powell */ 28928e37a85bf3dc39519942698dc90a3951306b934bAdam Powell public abstract void onRouteVolumeChanged(MediaRouter router, RouteInfo info); 289392130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown 289492130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown /** 289592130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * Called when a route's presentation display changes. 289692130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * <p> 289792130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * This method is called whenever the route's presentation display becomes 289892130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * available, is removes or has changes to some of its properties (such as its size). 289992130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * </p> 290092130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * 290192130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * @param router the MediaRouter reporting the event 290292130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * @param info The route whose presentation display changed 290392130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * 290492130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * @see RouteInfo#getPresentationDisplay() 290592130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown */ 290692130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown public void onRoutePresentationDisplayChanged(MediaRouter router, RouteInfo info) { 290792130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown } 29089a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 29099a1de308cea2d160778fd977825f10a07b49d738Adam Powell 29109a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 29110d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * Stub implementation of {@link MediaRouter.Callback}. 29120d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * Each abstract method is defined as a no-op. Override just the ones 29139a1de308cea2d160778fd977825f10a07b49d738Adam Powell * you need. 29149a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 29150d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public static class SimpleCallback extends Callback { 29169a1de308cea2d160778fd977825f10a07b49d738Adam Powell 29179a1de308cea2d160778fd977825f10a07b49d738Adam Powell @Override 2918d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell public void onRouteSelected(MediaRouter router, int type, RouteInfo info) { 29199a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 29209a1de308cea2d160778fd977825f10a07b49d738Adam Powell 29219a1de308cea2d160778fd977825f10a07b49d738Adam Powell @Override 2922d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell public void onRouteUnselected(MediaRouter router, int type, RouteInfo info) { 29239a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 29249a1de308cea2d160778fd977825f10a07b49d738Adam Powell 29259a1de308cea2d160778fd977825f10a07b49d738Adam Powell @Override 2926d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell public void onRouteAdded(MediaRouter router, RouteInfo info) { 29279a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 29289a1de308cea2d160778fd977825f10a07b49d738Adam Powell 29299a1de308cea2d160778fd977825f10a07b49d738Adam Powell @Override 2930d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell public void onRouteRemoved(MediaRouter router, RouteInfo info) { 29319a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 29329a1de308cea2d160778fd977825f10a07b49d738Adam Powell 29339a1de308cea2d160778fd977825f10a07b49d738Adam Powell @Override 2934d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell public void onRouteChanged(MediaRouter router, RouteInfo info) { 29359a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 29369a1de308cea2d160778fd977825f10a07b49d738Adam Powell 29379a1de308cea2d160778fd977825f10a07b49d738Adam Powell @Override 2938d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell public void onRouteGrouped(MediaRouter router, RouteInfo info, RouteGroup group, 2939d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell int index) { 29409a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 29419a1de308cea2d160778fd977825f10a07b49d738Adam Powell 29429a1de308cea2d160778fd977825f10a07b49d738Adam Powell @Override 2943d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell public void onRouteUngrouped(MediaRouter router, RouteInfo info, RouteGroup group) { 29449a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 2945d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell 29468e37a85bf3dc39519942698dc90a3951306b934bAdam Powell @Override 29478e37a85bf3dc39519942698dc90a3951306b934bAdam Powell public void onRouteVolumeChanged(MediaRouter router, RouteInfo info) { 29488e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 29499a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 29501357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 29511357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi static class VolumeCallbackInfo { 29521357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public final VolumeCallback vcb; 29531357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public final RouteInfo route; 29541357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 29551357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public VolumeCallbackInfo(VolumeCallback vcb, RouteInfo route) { 29561357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi this.vcb = vcb; 29571357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi this.route = route; 29581357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 29591357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 29601357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 29611357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 29621357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * Interface for receiving events about volume changes. 29631357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * All methods of this interface will be called from the application's main thread. 29641357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * 29651357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * <p>A VolumeCallback will only receive events relevant to routes that the callback 29661357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * was registered for.</p> 29671357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * 29681357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @see UserRouteInfo#setVolumeCallback(VolumeCallback) 29691357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 29701357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public static abstract class VolumeCallback { 29711357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 29721357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * Called when the volume for the route should be increased or decreased. 29731357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @param info the route affected by this event 29741357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @param direction an integer indicating whether the volume is to be increased 29751357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * (positive value) or decreased (negative value). 29761357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * For bundled changes, the absolute value indicates the number of changes 29771357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * in the same direction, e.g. +3 corresponds to three "volume up" changes. 29781357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 29791357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public abstract void onVolumeUpdateRequest(RouteInfo info, int direction); 29801357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 29811357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * Called when the volume for the route should be set to the given value 29821357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @param info the route affected by this event 29831357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @param volume an integer indicating the new volume value that should be used, always 29841357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * between 0 and the value set by {@link UserRouteInfo#setVolumeMax(int)}. 29851357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 29861357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public abstract void onVolumeSetRequest(RouteInfo info, int volume); 29871357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 29881357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 29898e37a85bf3dc39519942698dc90a3951306b934bAdam Powell static class VolumeChangeReceiver extends BroadcastReceiver { 29908e37a85bf3dc39519942698dc90a3951306b934bAdam Powell @Override 29918e37a85bf3dc39519942698dc90a3951306b934bAdam Powell public void onReceive(Context context, Intent intent) { 29928e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (intent.getAction().equals(AudioManager.VOLUME_CHANGED_ACTION)) { 29938e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final int streamType = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, 29948e37a85bf3dc39519942698dc90a3951306b934bAdam Powell -1); 29958e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (streamType != AudioManager.STREAM_MUSIC) { 29968e37a85bf3dc39519942698dc90a3951306b934bAdam Powell return; 29978e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 29988e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 29998e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final int newVolume = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, 0); 30008e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final int oldVolume = intent.getIntExtra( 30018e37a85bf3dc39519942698dc90a3951306b934bAdam Powell AudioManager.EXTRA_PREV_VOLUME_STREAM_VALUE, 0); 30028e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (newVolume != oldVolume) { 30038e37a85bf3dc39519942698dc90a3951306b934bAdam Powell systemVolumeChanged(newVolume); 30048e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 30058e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 30068e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 3007705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 30088e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 3009705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell static class WifiDisplayStatusChangedReceiver extends BroadcastReceiver { 3010705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell @Override 3011705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell public void onReceive(Context context, Intent intent) { 3012705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell if (intent.getAction().equals(DisplayManager.ACTION_WIFI_DISPLAY_STATUS_CHANGED)) { 3013705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell updateWifiDisplayStatus((WifiDisplayStatus) intent.getParcelableExtra( 3014705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell DisplayManager.EXTRA_WIFI_DISPLAY_STATUS)); 3015705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 3016705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 30178e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 30189a1de308cea2d160778fd977825f10a07b49d738Adam Powell} 3019