MediaRouter.java revision 4bad663518908c20ed4f93a27f46ffb09448497f
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) { 186742e379863ff08a880cb6d9e5f274da7589f9a53Jaewan Kim boolean updated = 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 } 200705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell sStatic.mDefaultAudioVideo.mNameResId = name; 201705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell dispatchRouteChanged(sStatic.mDefaultAudioVideo); 202742e379863ff08a880cb6d9e5f274da7589f9a53Jaewan Kim updated = true; 203632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } 204bcf21e913af7252fb1994e07b6cf179321ecd049Adam Powell 2056156017c2217d0fbbbb03434986250ec6bbd69d8John Spurlock final int mainType = mCurAudioRoutesInfo.mainType; 2063f369684e13dfea0ba8ea134f3e95930b0dd7df0Adam Powell 2076156017c2217d0fbbbb03434986250ec6bbd69d8John Spurlock if (!TextUtils.equals(newRoutes.bluetoothName, mCurAudioRoutesInfo.bluetoothName)) { 2086156017c2217d0fbbbb03434986250ec6bbd69d8John Spurlock mCurAudioRoutesInfo.bluetoothName = newRoutes.bluetoothName; 2096156017c2217d0fbbbb03434986250ec6bbd69d8John Spurlock if (mCurAudioRoutesInfo.bluetoothName != null) { 210632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn if (sStatic.mBluetoothA2dpRoute == null) { 211632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn final RouteInfo info = new RouteInfo(sStatic.mSystemCategory); 2126156017c2217d0fbbbb03434986250ec6bbd69d8John Spurlock info.mName = mCurAudioRoutesInfo.bluetoothName; 21356d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown info.mDescription = sStatic.mResources.getText( 21456d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown com.android.internal.R.string.bluetooth_a2dp_audio_route_name); 215632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn info.mSupportedTypes = ROUTE_TYPE_LIVE_AUDIO; 2169dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang info.mDeviceType = RouteInfo.DEVICE_TYPE_BLUETOOTH; 217632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn sStatic.mBluetoothA2dpRoute = info; 2182ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell addRouteStatic(sStatic.mBluetoothA2dpRoute); 219632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } else { 2206156017c2217d0fbbbb03434986250ec6bbd69d8John Spurlock sStatic.mBluetoothA2dpRoute.mName = mCurAudioRoutesInfo.bluetoothName; 221632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn dispatchRouteChanged(sStatic.mBluetoothA2dpRoute); 222632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } 223632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } else if (sStatic.mBluetoothA2dpRoute != null) { 22469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown removeRouteStatic(sStatic.mBluetoothA2dpRoute); 225632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn sStatic.mBluetoothA2dpRoute = null; 226632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } 227742e379863ff08a880cb6d9e5f274da7589f9a53Jaewan Kim updated = true; 228632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } 229bcf21e913af7252fb1994e07b6cf179321ecd049Adam Powell 230bcf21e913af7252fb1994e07b6cf179321ecd049Adam Powell if (mBluetoothA2dpRoute != null) { 231fa6f70e225a7370c1ecb21ee7076c9086ecb9e9aSungsoo final boolean a2dpEnabled = isBluetoothA2dpOn(); 23271f3563c3960bd862dfa96844f646ea5b2f03de5Sungsoo if (mSelectedRoute == mBluetoothA2dpRoute && !a2dpEnabled) { 233fa6f70e225a7370c1ecb21ee7076c9086ecb9e9aSungsoo selectRouteStatic(ROUTE_TYPE_LIVE_AUDIO, mDefaultAudioVideo, false); 234742e379863ff08a880cb6d9e5f274da7589f9a53Jaewan Kim updated = true; 235fa6f70e225a7370c1ecb21ee7076c9086ecb9e9aSungsoo } else if ((mSelectedRoute == mDefaultAudioVideo || mSelectedRoute == null) && 236fa6f70e225a7370c1ecb21ee7076c9086ecb9e9aSungsoo a2dpEnabled) { 23769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown selectRouteStatic(ROUTE_TYPE_LIVE_AUDIO, mBluetoothA2dpRoute, false); 238742e379863ff08a880cb6d9e5f274da7589f9a53Jaewan Kim updated = true; 239bcf21e913af7252fb1994e07b6cf179321ecd049Adam Powell } 240bcf21e913af7252fb1994e07b6cf179321ecd049Adam Powell } 241742e379863ff08a880cb6d9e5f274da7589f9a53Jaewan Kim if (updated) { 242742e379863ff08a880cb6d9e5f274da7589f9a53Jaewan Kim Log.v(TAG, "Audio routes updated: " + newRoutes + ", a2dp=" + isBluetoothA2dpOn()); 243742e379863ff08a880cb6d9e5f274da7589f9a53Jaewan Kim } 244b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn } 24592130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown 246fa6f70e225a7370c1ecb21ee7076c9086ecb9e9aSungsoo boolean isBluetoothA2dpOn() { 247fa6f70e225a7370c1ecb21ee7076c9086ecb9e9aSungsoo try { 248fa6f70e225a7370c1ecb21ee7076c9086ecb9e9aSungsoo return mAudioService.isBluetoothA2dpOn(); 249fa6f70e225a7370c1ecb21ee7076c9086ecb9e9aSungsoo } catch (RemoteException e) { 250fa6f70e225a7370c1ecb21ee7076c9086ecb9e9aSungsoo Log.e(TAG, "Error querying Bluetooth A2DP state", e); 251fa6f70e225a7370c1ecb21ee7076c9086ecb9e9aSungsoo return false; 252fa6f70e225a7370c1ecb21ee7076c9086ecb9e9aSungsoo } 253fa6f70e225a7370c1ecb21ee7076c9086ecb9e9aSungsoo } 254fa6f70e225a7370c1ecb21ee7076c9086ecb9e9aSungsoo 25569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown void updateDiscoveryRequest() { 25669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // What are we looking for today? 25769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown int routeTypes = 0; 25869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown int passiveRouteTypes = 0; 25969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown boolean activeScan = false; 26069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown boolean activeScanWifiDisplay = false; 26169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final int count = mCallbacks.size(); 26269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown for (int i = 0; i < count; i++) { 26369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown CallbackInfo cbi = mCallbacks.get(i); 26469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if ((cbi.flags & (CALLBACK_FLAG_PERFORM_ACTIVE_SCAN 26569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown | CALLBACK_FLAG_REQUEST_DISCOVERY)) != 0) { 26669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Discovery explicitly requested. 26769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown routeTypes |= cbi.type; 26869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } else if ((cbi.flags & CALLBACK_FLAG_PASSIVE_DISCOVERY) != 0) { 26969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Discovery only passively requested. 27069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown passiveRouteTypes |= cbi.type; 27169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } else { 27269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Legacy case since applications don't specify the discovery flag. 27369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Unfortunately we just have to assume they always need discovery 27469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // whenever they have a callback registered. 27569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown routeTypes |= cbi.type; 27669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 27769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if ((cbi.flags & CALLBACK_FLAG_PERFORM_ACTIVE_SCAN) != 0) { 27869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown activeScan = true; 279af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown if ((cbi.type & ROUTE_TYPE_REMOTE_DISPLAY) != 0) { 28069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown activeScanWifiDisplay = true; 28169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 28269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 28369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 28469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (routeTypes != 0 || activeScan) { 28569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // If someone else requests discovery then enable the passive listeners. 28669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // This is used by the MediaRouteButton and MediaRouteActionProvider since 28769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // they don't receive lifecycle callbacks from the Activity. 28869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown routeTypes |= passiveRouteTypes; 28969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 29069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 29169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Update wifi display scanning. 292ce468a35b388ca46578934706b38dbae94941643Jeff Brown // TODO: All of this should be managed by the media router service. 293ce468a35b388ca46578934706b38dbae94941643Jeff Brown if (mCanConfigureWifiDisplays) { 294ce468a35b388ca46578934706b38dbae94941643Jeff Brown if (mSelectedRoute != null 295ce468a35b388ca46578934706b38dbae94941643Jeff Brown && mSelectedRoute.matchesTypes(ROUTE_TYPE_REMOTE_DISPLAY)) { 296ce468a35b388ca46578934706b38dbae94941643Jeff Brown // Don't scan while already connected to a remote display since 297ce468a35b388ca46578934706b38dbae94941643Jeff Brown // it may interfere with the ongoing transmission. 298ce468a35b388ca46578934706b38dbae94941643Jeff Brown activeScanWifiDisplay = false; 29966f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown } 300ce468a35b388ca46578934706b38dbae94941643Jeff Brown if (activeScanWifiDisplay) { 301ce468a35b388ca46578934706b38dbae94941643Jeff Brown if (!mActivelyScanningWifiDisplays) { 302ce468a35b388ca46578934706b38dbae94941643Jeff Brown mActivelyScanningWifiDisplays = true; 303ce468a35b388ca46578934706b38dbae94941643Jeff Brown mDisplayService.startWifiDisplayScan(); 304ce468a35b388ca46578934706b38dbae94941643Jeff Brown } 305ce468a35b388ca46578934706b38dbae94941643Jeff Brown } else { 306ce468a35b388ca46578934706b38dbae94941643Jeff Brown if (mActivelyScanningWifiDisplays) { 307ce468a35b388ca46578934706b38dbae94941643Jeff Brown mActivelyScanningWifiDisplays = false; 308ce468a35b388ca46578934706b38dbae94941643Jeff Brown mDisplayService.stopWifiDisplayScan(); 309ce468a35b388ca46578934706b38dbae94941643Jeff Brown } 31066f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown } 31166f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown } 31266f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown 31369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Tell the media router service all about it. 31469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (routeTypes != mDiscoveryRequestRouteTypes 31569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown || activeScan != mDiscoverRequestActiveScan) { 31669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mDiscoveryRequestRouteTypes = routeTypes; 31769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mDiscoverRequestActiveScan = activeScan; 31869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown publishClientDiscoveryRequest(); 31966f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown } 32066f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown } 32166f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown 32292130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown @Override 32392130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown public void onDisplayAdded(int displayId) { 32492130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown updatePresentationDisplays(displayId); 32592130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown } 32692130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown 32792130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown @Override 32892130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown public void onDisplayChanged(int displayId) { 32992130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown updatePresentationDisplays(displayId); 33092130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown } 33192130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown 33292130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown @Override 33392130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown public void onDisplayRemoved(int displayId) { 33492130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown updatePresentationDisplays(displayId); 33592130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown } 33692130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown 33792130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown public Display[] getAllPresentationDisplays() { 33892130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown return mDisplayService.getDisplays(DisplayManager.DISPLAY_CATEGORY_PRESENTATION); 33992130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown } 34092130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown 34192130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown private void updatePresentationDisplays(int changedDisplayId) { 34292130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown final int count = mRoutes.size(); 34392130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown for (int i = 0; i < count; i++) { 3445830b0b33618940d65197cec99d697b21908fec8Chong Zhang final RouteInfo route = mRoutes.get(i); 3455830b0b33618940d65197cec99d697b21908fec8Chong Zhang if (route.updatePresentationDisplay() || (route.mPresentationDisplay != null 3465830b0b33618940d65197cec99d697b21908fec8Chong Zhang && route.mPresentationDisplay.getDisplayId() == changedDisplayId)) { 3475830b0b33618940d65197cec99d697b21908fec8Chong Zhang dispatchRoutePresentationDisplayChanged(route); 34892130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown } 34992130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown } 35092130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown } 35169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 35269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown void setSelectedRoute(RouteInfo info, boolean explicit) { 35369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Must be non-reentrant. 35469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mSelectedRoute = info; 35569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown publishClientSelectedRoute(explicit); 35669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 35769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 35869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown void rebindAsUser(int userId) { 35969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (mCurrentUserId != userId || userId < 0 || mClient == null) { 36069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (mClient != null) { 36169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown try { 36269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mMediaRouterService.unregisterClient(mClient); 36369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } catch (RemoteException ex) { 36469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Log.e(TAG, "Unable to unregister media router client.", ex); 36569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 36669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mClient = null; 36769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 36869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 36969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mCurrentUserId = userId; 37069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 37169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown try { 37269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Client client = new Client(); 373eadd6d2329972129c96dee390a8b786b37313d17Hyundo Moon mMediaRouterService.registerClientAsUser(client, mPackageName, userId); 37469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mClient = client; 37569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } catch (RemoteException ex) { 37669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Log.e(TAG, "Unable to register media router client.", ex); 37769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 37869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 37969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown publishClientDiscoveryRequest(); 38069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown publishClientSelectedRoute(false); 38169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown updateClientState(); 38269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 38369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 38469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 38569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown void publishClientDiscoveryRequest() { 38669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (mClient != null) { 38769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown try { 38869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mMediaRouterService.setDiscoveryRequest(mClient, 38969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mDiscoveryRequestRouteTypes, mDiscoverRequestActiveScan); 39069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } catch (RemoteException ex) { 39169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Log.e(TAG, "Unable to publish media router client discovery request.", ex); 39269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 39369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 39469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 39569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 39669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown void publishClientSelectedRoute(boolean explicit) { 39769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (mClient != null) { 39869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown try { 39969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mMediaRouterService.setSelectedRoute(mClient, 40069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mSelectedRoute != null ? mSelectedRoute.mGlobalRouteId : null, 40169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown explicit); 40269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } catch (RemoteException ex) { 40369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Log.e(TAG, "Unable to publish media router client selected route.", ex); 40469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 40569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 40669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 40769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 40869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown void updateClientState() { 40969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Update the client state. 41069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mClientState = null; 41169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (mClient != null) { 41269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown try { 41369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mClientState = mMediaRouterService.getState(mClient); 41469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } catch (RemoteException ex) { 41569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Log.e(TAG, "Unable to retrieve media router client state.", ex); 41669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 41769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 41869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final ArrayList<MediaRouterClientState.RouteInfo> globalRoutes = 41969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mClientState != null ? mClientState.routes : null; 42069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final String globallySelectedRouteId = mClientState != null ? 42169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mClientState.globallySelectedRouteId : null; 42269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 42369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Add or update routes. 42469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final int globalRouteCount = globalRoutes != null ? globalRoutes.size() : 0; 42569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown for (int i = 0; i < globalRouteCount; i++) { 42669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final MediaRouterClientState.RouteInfo globalRoute = globalRoutes.get(i); 42769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown RouteInfo route = findGlobalRoute(globalRoute.id); 42869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (route == null) { 42969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route = makeGlobalRoute(globalRoute); 43069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown addRouteStatic(route); 43169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } else { 43269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown updateGlobalRoute(route, globalRoute); 43369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 43469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 43569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 43669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Synchronize state with the globally selected route. 43769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (globallySelectedRouteId != null) { 43869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final RouteInfo route = findGlobalRoute(globallySelectedRouteId); 43969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (route == null) { 44069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Log.w(TAG, "Could not find new globally selected route: " 44169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown + globallySelectedRouteId); 44269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } else if (route != mSelectedRoute) { 44369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (DEBUG) { 44469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Log.d(TAG, "Selecting new globally selected route: " + route); 44569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 44669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown selectRouteStatic(route.mSupportedTypes, route, false); 44769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 44869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } else if (mSelectedRoute != null && mSelectedRoute.mGlobalRouteId != null) { 44969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (DEBUG) { 45069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Log.d(TAG, "Unselecting previous globally selected route: " + mSelectedRoute); 45169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 45269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown selectDefaultRouteStatic(); 45369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 45469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 45569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Remove defunct routes. 45669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown outer: for (int i = mRoutes.size(); i-- > 0; ) { 45769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final RouteInfo route = mRoutes.get(i); 45869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final String globalRouteId = route.mGlobalRouteId; 45969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (globalRouteId != null) { 46069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown for (int j = 0; j < globalRouteCount; j++) { 46169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown MediaRouterClientState.RouteInfo globalRoute = globalRoutes.get(j); 46269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (globalRouteId.equals(globalRoute.id)) { 46369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown continue outer; // found 46469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 46569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 46669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // not found 46769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown removeRouteStatic(route); 46869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 46969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 47069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 47169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 47269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown void requestSetVolume(RouteInfo route, int volume) { 47369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (route.mGlobalRouteId != null && mClient != null) { 47469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown try { 47569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mMediaRouterService.requestSetVolume(mClient, 47669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mGlobalRouteId, volume); 47769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } catch (RemoteException ex) { 47869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Log.w(TAG, "Unable to request volume change.", ex); 47969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 48069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 48169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 48269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 48369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown void requestUpdateVolume(RouteInfo route, int direction) { 48469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (route.mGlobalRouteId != null && mClient != null) { 48569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown try { 48669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mMediaRouterService.requestUpdateVolume(mClient, 48769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mGlobalRouteId, direction); 48869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } catch (RemoteException ex) { 48969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Log.w(TAG, "Unable to request volume change.", ex); 49069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 49169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 49269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 49369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 49469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown RouteInfo makeGlobalRoute(MediaRouterClientState.RouteInfo globalRoute) { 49569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown RouteInfo route = new RouteInfo(sStatic.mSystemCategory); 49669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mGlobalRouteId = globalRoute.id; 49769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mName = globalRoute.name; 49869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mDescription = globalRoute.description; 49969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mSupportedTypes = globalRoute.supportedTypes; 5009dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang route.mDeviceType = globalRoute.deviceType; 50169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mEnabled = globalRoute.enabled; 50239ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown route.setRealStatusCode(globalRoute.statusCode); 50369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mPlaybackType = globalRoute.playbackType; 50469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mPlaybackStream = globalRoute.playbackStream; 50569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mVolume = globalRoute.volume; 50669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mVolumeMax = globalRoute.volumeMax; 50769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mVolumeHandling = globalRoute.volumeHandling; 5085830b0b33618940d65197cec99d697b21908fec8Chong Zhang route.mPresentationDisplayId = globalRoute.presentationDisplayId; 5095830b0b33618940d65197cec99d697b21908fec8Chong Zhang route.updatePresentationDisplay(); 51069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return route; 51169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 51269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 51369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown void updateGlobalRoute(RouteInfo route, MediaRouterClientState.RouteInfo globalRoute) { 51469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown boolean changed = false; 51569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown boolean volumeChanged = false; 51669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown boolean presentationDisplayChanged = false; 51769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 518e6585b32ea586743258a5457e2184ffc087f2d2fKenny Root if (!Objects.equals(route.mName, globalRoute.name)) { 51969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mName = globalRoute.name; 52069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown changed = true; 52169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 522e6585b32ea586743258a5457e2184ffc087f2d2fKenny Root if (!Objects.equals(route.mDescription, globalRoute.description)) { 52369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mDescription = globalRoute.description; 52469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown changed = true; 52569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 526af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown final int oldSupportedTypes = route.mSupportedTypes; 527af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown if (oldSupportedTypes != globalRoute.supportedTypes) { 52869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mSupportedTypes = globalRoute.supportedTypes; 52969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown changed = true; 53069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 53169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (route.mEnabled != globalRoute.enabled) { 53269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mEnabled = globalRoute.enabled; 53369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown changed = true; 53469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 53539ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown if (route.mRealStatusCode != globalRoute.statusCode) { 53639ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown route.setRealStatusCode(globalRoute.statusCode); 53769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown changed = true; 53869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 53969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (route.mPlaybackType != globalRoute.playbackType) { 54069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mPlaybackType = globalRoute.playbackType; 54169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown changed = true; 54269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 54369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (route.mPlaybackStream != globalRoute.playbackStream) { 54469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mPlaybackStream = globalRoute.playbackStream; 54569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown changed = true; 54669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 54769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (route.mVolume != globalRoute.volume) { 54869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mVolume = globalRoute.volume; 54969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown changed = true; 55069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown volumeChanged = true; 55169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 55269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (route.mVolumeMax != globalRoute.volumeMax) { 55369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mVolumeMax = globalRoute.volumeMax; 55469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown changed = true; 55569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown volumeChanged = true; 55669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 55769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (route.mVolumeHandling != globalRoute.volumeHandling) { 55869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.mVolumeHandling = globalRoute.volumeHandling; 55969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown changed = true; 56069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown volumeChanged = true; 56169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 5625830b0b33618940d65197cec99d697b21908fec8Chong Zhang if (route.mPresentationDisplayId != globalRoute.presentationDisplayId) { 5635830b0b33618940d65197cec99d697b21908fec8Chong Zhang route.mPresentationDisplayId = globalRoute.presentationDisplayId; 5645830b0b33618940d65197cec99d697b21908fec8Chong Zhang route.updatePresentationDisplay(); 56569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown changed = true; 56669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown presentationDisplayChanged = true; 56769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 56869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 56969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (changed) { 570af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown dispatchRouteChanged(route, oldSupportedTypes); 57169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 57269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (volumeChanged) { 57369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown dispatchRouteVolumeChanged(route); 57469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 57569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (presentationDisplayChanged) { 57669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown dispatchRoutePresentationDisplayChanged(route); 57769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 57869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 57969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 58069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown RouteInfo findGlobalRoute(String globalRouteId) { 58169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final int count = mRoutes.size(); 58269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown for (int i = 0; i < count; i++) { 58369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final RouteInfo route = mRoutes.get(i); 58469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (globalRouteId.equals(route.mGlobalRouteId)) { 58569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return route; 58669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 58769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 58869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return null; 58969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 59069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 59169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final class Client extends IMediaRouterClient.Stub { 59269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown @Override 59369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public void onStateChanged() { 59469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mHandler.post(new Runnable() { 59569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown @Override 59669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public void run() { 59769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (Client.this == mClient) { 59869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown updateClientState(); 59969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 60069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 60169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown }); 60269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 60369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 604b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn } 6059a1de308cea2d160778fd977825f10a07b49d738Adam Powell 606b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn static Static sStatic; 6079a1de308cea2d160778fd977825f10a07b49d738Adam Powell 6089a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 6099a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Route type flag for live audio. 6109a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 6119a1de308cea2d160778fd977825f10a07b49d738Adam Powell * <p>A device that supports live audio routing will allow the media audio stream 6129a1de308cea2d160778fd977825f10a07b49d738Adam Powell * to be routed to supported destinations. This can include internal speakers or 6139a1de308cea2d160778fd977825f10a07b49d738Adam Powell * audio jacks on the device itself, A2DP devices, and more.</p> 6149a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 6159a1de308cea2d160778fd977825f10a07b49d738Adam Powell * <p>Once initiated this routing is transparent to the application. All audio 6169a1de308cea2d160778fd977825f10a07b49d738Adam Powell * played on the media stream will be routed to the selected destination.</p> 6179a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 61869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public static final int ROUTE_TYPE_LIVE_AUDIO = 1 << 0; 6199a1de308cea2d160778fd977825f10a07b49d738Adam Powell 6209a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 621705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell * Route type flag for live video. 622705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell * 623705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell * <p>A device that supports live video routing will allow a mirrored version 624705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell * of the device's primary display or a customized 625705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell * {@link android.app.Presentation Presentation} to be routed to supported destinations.</p> 626705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell * 627705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell * <p>Once initiated, display mirroring is transparent to the application. 628705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell * While remote routing is active the application may use a 629705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell * {@link android.app.Presentation Presentation} to replace the mirrored view 630705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell * on the external display with different content.</p> 63192130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * 63292130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * @see RouteInfo#getPresentationDisplay() 63392130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * @see android.app.Presentation 634705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell */ 63569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public static final int ROUTE_TYPE_LIVE_VIDEO = 1 << 1; 63669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 63769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown /** 63869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * Temporary interop constant to identify remote displays. 63969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * @hide To be removed when media router API is updated. 64069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown */ 64169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public static final int ROUTE_TYPE_REMOTE_DISPLAY = 1 << 2; 642705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 643705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell /** 6449a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Route type flag for application-specific usage. 6459a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 6469a1de308cea2d160778fd977825f10a07b49d738Adam Powell * <p>Unlike other media route types, user routes are managed by the application. 6479a1de308cea2d160778fd977825f10a07b49d738Adam Powell * The MediaRouter will manage and dispatch events for user routes, but the application 6489a1de308cea2d160778fd977825f10a07b49d738Adam Powell * is expected to interpret the meaning of these events and perform the requested 6499a1de308cea2d160778fd977825f10a07b49d738Adam Powell * routing tasks.</p> 6509a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 65169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public static final int ROUTE_TYPE_USER = 1 << 23; 65269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 65369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown static final int ROUTE_TYPE_ANY = ROUTE_TYPE_LIVE_AUDIO | ROUTE_TYPE_LIVE_VIDEO 65469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown | ROUTE_TYPE_REMOTE_DISPLAY | ROUTE_TYPE_USER; 6559a1de308cea2d160778fd977825f10a07b49d738Adam Powell 65666f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown /** 65766f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * Flag for {@link #addCallback}: Actively scan for routes while this callback 65866f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * is registered. 65966f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * <p> 66066f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * When this flag is specified, the media router will actively scan for new 66166f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * routes. Certain routes, such as wifi display routes, may not be discoverable 66266f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * except when actively scanning. This flag is typically used when the route picker 66366f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * dialog has been opened by the user to ensure that the route information is 66466f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * up to date. 66566f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * </p><p> 66666f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * Active scanning may consume a significant amount of power and may have intrusive 66766f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * effects on wireless connectivity. Therefore it is important that active scanning 66866f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * only be requested when it is actually needed to satisfy a user request to 66966f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * discover and select a new route. 67066f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * </p> 67166f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown */ 67214507e257af5d71577574e25cbd690c4b54c9272Jeff Brown public static final int CALLBACK_FLAG_PERFORM_ACTIVE_SCAN = 1 << 0; 67366f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown 67466f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown /** 67566f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * Flag for {@link #addCallback}: Do not filter route events. 67666f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * <p> 67766f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * When this flag is specified, the callback will be invoked for event that affect any 67869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * route even if they do not match the callback's filter. 67966f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * </p> 68066f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown */ 68166f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown public static final int CALLBACK_FLAG_UNFILTERED_EVENTS = 1 << 1; 68266f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown 68369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown /** 68469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * Explicitly requests discovery. 68569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * 68669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * @hide Future API ported from support library. Revisit this later. 68769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown */ 68869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public static final int CALLBACK_FLAG_REQUEST_DISCOVERY = 1 << 2; 68969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 69069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown /** 69169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * Requests that discovery be performed but only if there is some other active 69269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * callback already registered. 69369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * 69469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * @hide Compatibility workaround for the fact that applications do not currently 69569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * request discovery explicitly (except when using the support library API). 69669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown */ 69769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public static final int CALLBACK_FLAG_PASSIVE_DISCOVERY = 1 << 3; 69869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 6990abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown /** 7000abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * Flag for {@link #isRouteAvailable}: Ignore the default route. 7010abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * <p> 7020abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * This flag is used to determine whether a matching non-default route is available. 7030abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * This constraint may be used to decide whether to offer the route chooser dialog 7040abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * to the user. There is no point offering the chooser if there are no 7050abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * non-default choices. 7060abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * </p> 7070abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * 7080abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * @hide Future API ported from support library. Revisit this later. 7090abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown */ 7100abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown public static final int AVAILABILITY_FLAG_IGNORE_DEFAULT_ROUTE = 1 << 0; 7110abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown 7129a1de308cea2d160778fd977825f10a07b49d738Adam Powell // Maps application contexts 7139a1de308cea2d160778fd977825f10a07b49d738Adam Powell static final HashMap<Context, MediaRouter> sRouters = new HashMap<Context, MediaRouter>(); 7149a1de308cea2d160778fd977825f10a07b49d738Adam Powell 7159a1de308cea2d160778fd977825f10a07b49d738Adam Powell static String typesToString(int types) { 7169a1de308cea2d160778fd977825f10a07b49d738Adam Powell final StringBuilder result = new StringBuilder(); 7179a1de308cea2d160778fd977825f10a07b49d738Adam Powell if ((types & ROUTE_TYPE_LIVE_AUDIO) != 0) { 7189a1de308cea2d160778fd977825f10a07b49d738Adam Powell result.append("ROUTE_TYPE_LIVE_AUDIO "); 7199a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 7202bb7c122ef6ce8539dfbaeb3292adcd942185f82Bryan Mawhinney if ((types & ROUTE_TYPE_LIVE_VIDEO) != 0) { 7212bb7c122ef6ce8539dfbaeb3292adcd942185f82Bryan Mawhinney result.append("ROUTE_TYPE_LIVE_VIDEO "); 7222bb7c122ef6ce8539dfbaeb3292adcd942185f82Bryan Mawhinney } 72369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if ((types & ROUTE_TYPE_REMOTE_DISPLAY) != 0) { 72469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown result.append("ROUTE_TYPE_REMOTE_DISPLAY "); 72569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 7269a1de308cea2d160778fd977825f10a07b49d738Adam Powell if ((types & ROUTE_TYPE_USER) != 0) { 7279a1de308cea2d160778fd977825f10a07b49d738Adam Powell result.append("ROUTE_TYPE_USER "); 7289a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 7299a1de308cea2d160778fd977825f10a07b49d738Adam Powell return result.toString(); 7309a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 7319a1de308cea2d160778fd977825f10a07b49d738Adam Powell 732b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn /** @hide */ 733b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn public MediaRouter(Context context) { 734b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn synchronized (Static.class) { 735b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn if (sStatic == null) { 7368e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final Context appContext = context.getApplicationContext(); 7378e37a85bf3dc39519942698dc90a3951306b934bAdam Powell sStatic = new Static(appContext); 7388e37a85bf3dc39519942698dc90a3951306b934bAdam Powell sStatic.startMonitoringRoutes(appContext); 739b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn } 7409a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 7419a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 7429a1de308cea2d160778fd977825f10a07b49d738Adam Powell 743690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell /** 7443afc18af2cea898753b10e8575dcf20c11356bcaJeff Brown * Gets the default route for playing media content on the system. 7453afc18af2cea898753b10e8575dcf20c11356bcaJeff Brown * <p> 7463afc18af2cea898753b10e8575dcf20c11356bcaJeff Brown * The system always provides a default route. 7473afc18af2cea898753b10e8575dcf20c11356bcaJeff Brown * </p> 7483afc18af2cea898753b10e8575dcf20c11356bcaJeff Brown * 7493afc18af2cea898753b10e8575dcf20c11356bcaJeff Brown * @return The default route, which is guaranteed to never be null. 750690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell */ 7513afc18af2cea898753b10e8575dcf20c11356bcaJeff Brown public RouteInfo getDefaultRoute() { 752705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell return sStatic.mDefaultAudioVideo; 753690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell } 754690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell 755690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell /** 7564599696591f745b3a546197d2ba7e5cfc5562484Adam Powell * @hide for use by framework routing UI 7574599696591f745b3a546197d2ba7e5cfc5562484Adam Powell */ 7583afc18af2cea898753b10e8575dcf20c11356bcaJeff Brown public RouteCategory getSystemCategory() { 7594599696591f745b3a546197d2ba7e5cfc5562484Adam Powell return sStatic.mSystemCategory; 7604599696591f745b3a546197d2ba7e5cfc5562484Adam Powell } 7614599696591f745b3a546197d2ba7e5cfc5562484Adam Powell 7620abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown /** @hide */ 7630abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown public RouteInfo getSelectedRoute() { 7640abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown return getSelectedRoute(ROUTE_TYPE_ANY); 7650abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown } 7660abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown 7674599696591f745b3a546197d2ba7e5cfc5562484Adam Powell /** 7681cf2ca83584a4cf0aa3ded787bd191b9a60e3521Adam Powell * Return the currently selected route for any of the given types 769690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell * 770690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell * @param type route types 771690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell * @return the selected route 772690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell */ 773690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell public RouteInfo getSelectedRoute(int type) { 7741cf2ca83584a4cf0aa3ded787bd191b9a60e3521Adam Powell if (sStatic.mSelectedRoute != null && 7751cf2ca83584a4cf0aa3ded787bd191b9a60e3521Adam Powell (sStatic.mSelectedRoute.mSupportedTypes & type) != 0) { 7761cf2ca83584a4cf0aa3ded787bd191b9a60e3521Adam Powell // If the selected route supports any of the types supplied, it's still considered 7771cf2ca83584a4cf0aa3ded787bd191b9a60e3521Adam Powell // 'selected' for that type. 7781cf2ca83584a4cf0aa3ded787bd191b9a60e3521Adam Powell return sStatic.mSelectedRoute; 7791cf2ca83584a4cf0aa3ded787bd191b9a60e3521Adam Powell } else if (type == ROUTE_TYPE_USER) { 7801cf2ca83584a4cf0aa3ded787bd191b9a60e3521Adam Powell // The caller specifically asked for a user route and the currently selected route 7811cf2ca83584a4cf0aa3ded787bd191b9a60e3521Adam Powell // doesn't qualify. 7821cf2ca83584a4cf0aa3ded787bd191b9a60e3521Adam Powell return null; 7831cf2ca83584a4cf0aa3ded787bd191b9a60e3521Adam Powell } 7841cf2ca83584a4cf0aa3ded787bd191b9a60e3521Adam Powell // If the above didn't match and we're not specifically asking for a user route, 7851cf2ca83584a4cf0aa3ded787bd191b9a60e3521Adam Powell // consider the default selected. 7861cf2ca83584a4cf0aa3ded787bd191b9a60e3521Adam Powell return sStatic.mDefaultAudioVideo; 787690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell } 788690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell 7899a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 7900abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * Returns true if there is a route that matches the specified types. 7910abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * <p> 7920abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * This method returns true if there are any available routes that match the types 7930abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * regardless of whether they are enabled or disabled. If the 7940abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * {@link #AVAILABILITY_FLAG_IGNORE_DEFAULT_ROUTE} flag is specified, then 7950abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * the method will only consider non-default routes. 7960abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * </p> 7970abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * 7980abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * @param types The types to match. 7990abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * @param flags Flags to control the determination of whether a route may be available. 8000abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * May be zero or {@link #AVAILABILITY_FLAG_IGNORE_DEFAULT_ROUTE}. 8010abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * @return True if a matching route may be available. 8020abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * 8030abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown * @hide Future API ported from support library. Revisit this later. 8040abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown */ 8050abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown public boolean isRouteAvailable(int types, int flags) { 8060abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown final int count = sStatic.mRoutes.size(); 8070abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown for (int i = 0; i < count; i++) { 8080abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown RouteInfo route = sStatic.mRoutes.get(i); 8090abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown if (route.matchesTypes(types)) { 8100abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown if ((flags & AVAILABILITY_FLAG_IGNORE_DEFAULT_ROUTE) == 0 8110abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown || route != sStatic.mDefaultAudioVideo) { 8120abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown return true; 8130abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown } 8140abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown } 8150abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown } 8160abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown 8170abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown // It doesn't look like we can find a matching route right now. 8180abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown return false; 8190abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown } 8200abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown 8210abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown /** 8229a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Add a callback to listen to events about specific kinds of media routes. 8239a1de308cea2d160778fd977825f10a07b49d738Adam Powell * If the specified callback is already registered, its registration will be updated for any 8249a1de308cea2d160778fd977825f10a07b49d738Adam Powell * additional route types specified. 82566f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * <p> 82666f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * This is a convenience method that has the same effect as calling 82766f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * {@link #addCallback(int, Callback, int)} without flags. 82866f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * </p> 8299a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 8309a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param types Types of routes this callback is interested in 8319a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param cb Callback to add 8329a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 8339a1de308cea2d160778fd977825f10a07b49d738Adam Powell public void addCallback(int types, Callback cb) { 83466f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown addCallback(types, cb, 0); 83566f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown } 83666f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown 83766f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown /** 83866f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * Add a callback to listen to events about specific kinds of media routes. 83966f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * If the specified callback is already registered, its registration will be updated for any 84066f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * additional route types specified. 84166f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * <p> 84266f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * By default, the callback will only be invoked for events that affect routes 84366f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * that match the specified selector. The filtering may be disabled by specifying 84466f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * the {@link #CALLBACK_FLAG_UNFILTERED_EVENTS} flag. 84566f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * </p> 84666f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * 84766f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * @param types Types of routes this callback is interested in 84866f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * @param cb Callback to add 84966f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * @param flags Flags to control the behavior of the callback. 85014507e257af5d71577574e25cbd690c4b54c9272Jeff Brown * May be zero or a combination of {@link #CALLBACK_FLAG_PERFORM_ACTIVE_SCAN} and 85166f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * {@link #CALLBACK_FLAG_UNFILTERED_EVENTS}. 85266f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown */ 85366f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown public void addCallback(int types, Callback cb, int flags) { 85466f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown CallbackInfo info; 85566f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown int index = findCallbackInfo(cb); 85666f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown if (index >= 0) { 85766f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown info = sStatic.mCallbacks.get(index); 85866f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown info.type |= types; 85966f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown info.flags |= flags; 86066f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown } else { 86166f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown info = new CallbackInfo(cb, types, flags, this); 86266f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown sStatic.mCallbacks.add(info); 86366f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown } 86469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown sStatic.updateDiscoveryRequest(); 8659a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 8669a1de308cea2d160778fd977825f10a07b49d738Adam Powell 8679a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 8689a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Remove the specified callback. It will no longer receive events about media routing. 8699a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 8709a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param cb Callback to remove 8719a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 8729a1de308cea2d160778fd977825f10a07b49d738Adam Powell public void removeCallback(Callback cb) { 87366f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown int index = findCallbackInfo(cb); 87466f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown if (index >= 0) { 87569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown sStatic.mCallbacks.remove(index); 87669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown sStatic.updateDiscoveryRequest(); 87766f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown } else { 87866f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown Log.w(TAG, "removeCallback(" + cb + "): callback not registered"); 87966f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown } 88066f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown } 88166f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown 88266f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown private int findCallbackInfo(Callback cb) { 883b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn final int count = sStatic.mCallbacks.size(); 8849a1de308cea2d160778fd977825f10a07b49d738Adam Powell for (int i = 0; i < count; i++) { 88566f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown final CallbackInfo info = sStatic.mCallbacks.get(i); 88666f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown if (info.cb == cb) { 88766f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown return i; 8889a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 8899a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 89066f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown return -1; 8919a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 8929a1de308cea2d160778fd977825f10a07b49d738Adam Powell 893d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell /** 894d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * Select the specified route to use for output of the given media types. 8953afc18af2cea898753b10e8575dcf20c11356bcaJeff Brown * <p class="note"> 8963afc18af2cea898753b10e8575dcf20c11356bcaJeff Brown * As API version 18, this function may be used to select any route. 8973afc18af2cea898753b10e8575dcf20c11356bcaJeff Brown * In prior versions, this function could only be used to select user 8983afc18af2cea898753b10e8575dcf20c11356bcaJeff Brown * routes and would ignore any attempt to select a system route. 8993afc18af2cea898753b10e8575dcf20c11356bcaJeff Brown * </p> 900d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * 901d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param types type flags indicating which types this route should be used for. 902d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * The route must support at least a subset. 903d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param route Route to select 9049d93a378c5158d14f80d46af70433234330ec568P.Y. Laligand * @throws IllegalArgumentException if the given route is {@code null} 905d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell */ 9069d93a378c5158d14f80d46af70433234330ec568P.Y. Laligand public void selectRoute(int types, @NonNull RouteInfo route) { 9079d93a378c5158d14f80d46af70433234330ec568P.Y. Laligand if (route == null) { 9089d93a378c5158d14f80d46af70433234330ec568P.Y. Laligand throw new IllegalArgumentException("Route cannot be null."); 9099d93a378c5158d14f80d46af70433234330ec568P.Y. Laligand } 91069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown selectRouteStatic(types, route, true); 9110d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell } 91269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 9130d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell /** 9140d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * @hide internal use 9150d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell */ 91669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public void selectRouteInt(int types, RouteInfo route, boolean explicit) { 91769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown selectRouteStatic(types, route, explicit); 918b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn } 919b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn 9209d93a378c5158d14f80d46af70433234330ec568P.Y. Laligand static void selectRouteStatic(int types, @NonNull RouteInfo route, boolean explicit) { 92118687b7a275b3782e63d52cdbe8ee9df191046e7Jae Seo Log.v(TAG, "Selecting route: " + route); 9229d93a378c5158d14f80d46af70433234330ec568P.Y. Laligand assert(route != null); 923705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell final RouteInfo oldRoute = sStatic.mSelectedRoute; 924705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell if (oldRoute == route) return; 9250abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown if (!route.matchesTypes(types)) { 9260d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell Log.w(TAG, "selectRoute ignored; cannot select route with supported types " + 9270d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell typesToString(route.getSupportedTypes()) + " into route types " + 9280d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell typesToString(types)); 9294ee1f55ce0f4909a7430ab44563a81852f335071Adam Powell return; 9300d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell } 9319a1de308cea2d160778fd977825f10a07b49d738Adam Powell 932fa6f70e225a7370c1ecb21ee7076c9086ecb9e9aSungsoo final RouteInfo btRoute = sStatic.mBluetoothA2dpRoute; 933fa6f70e225a7370c1ecb21ee7076c9086ecb9e9aSungsoo if (btRoute != null && (types & ROUTE_TYPE_LIVE_AUDIO) != 0 && 934fa6f70e225a7370c1ecb21ee7076c9086ecb9e9aSungsoo (route == btRoute || route == sStatic.mDefaultAudioVideo)) { 935fa6f70e225a7370c1ecb21ee7076c9086ecb9e9aSungsoo try { 936fa6f70e225a7370c1ecb21ee7076c9086ecb9e9aSungsoo sStatic.mAudioService.setBluetoothA2dpOn(route == btRoute); 937fa6f70e225a7370c1ecb21ee7076c9086ecb9e9aSungsoo } catch (RemoteException e) { 938fa6f70e225a7370c1ecb21ee7076c9086ecb9e9aSungsoo Log.e(TAG, "Error changing Bluetooth A2DP state", e); 939fa6f70e225a7370c1ecb21ee7076c9086ecb9e9aSungsoo } 940fa6f70e225a7370c1ecb21ee7076c9086ecb9e9aSungsoo } 941fa6f70e225a7370c1ecb21ee7076c9086ecb9e9aSungsoo 942705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell final WifiDisplay activeDisplay = 943705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell sStatic.mDisplayService.getWifiDisplayStatus().getActiveDisplay(); 944705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell final boolean oldRouteHasAddress = oldRoute != null && oldRoute.mDeviceAddress != null; 9459d93a378c5158d14f80d46af70433234330ec568P.Y. Laligand final boolean newRouteHasAddress = route.mDeviceAddress != null; 946705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell if (activeDisplay != null || oldRouteHasAddress || newRouteHasAddress) { 947705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell if (newRouteHasAddress && !matchesDeviceAddress(activeDisplay, route)) { 948af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown if (sStatic.mCanConfigureWifiDisplays) { 949af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown sStatic.mDisplayService.connectWifiDisplay(route.mDeviceAddress); 950af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown } else { 951af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown Log.e(TAG, "Cannot connect to wifi displays because this process " 952af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown + "is not allowed to do so."); 953af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown } 954705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } else if (activeDisplay != null && !newRouteHasAddress) { 955705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell sStatic.mDisplayService.disconnectWifiDisplay(); 956705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 957705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 958705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 95969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown sStatic.setSelectedRoute(route, explicit); 96069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 961705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell if (oldRoute != null) { 962705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell dispatchRouteUnselected(types & oldRoute.getSupportedTypes(), oldRoute); 96339ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown if (oldRoute.resolveStatusCode()) { 96439ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown dispatchRouteChanged(oldRoute); 96539ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown } 9669a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 9679a1de308cea2d160778fd977825f10a07b49d738Adam Powell if (route != null) { 96839ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown if (route.resolveStatusCode()) { 96939ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown dispatchRouteChanged(route); 97039ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown } 9719a1de308cea2d160778fd977825f10a07b49d738Adam Powell dispatchRouteSelected(types & route.getSupportedTypes(), route); 9729a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 973ce468a35b388ca46578934706b38dbae94941643Jeff Brown 974ce468a35b388ca46578934706b38dbae94941643Jeff Brown // The behavior of active scans may depend on the currently selected route. 975ce468a35b388ca46578934706b38dbae94941643Jeff Brown sStatic.updateDiscoveryRequest(); 9769a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 9779a1de308cea2d160778fd977825f10a07b49d738Adam Powell 97869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown static void selectDefaultRouteStatic() { 97969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // TODO: Be smarter about the route types here; this selects for all valid. 98069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (sStatic.mSelectedRoute != sStatic.mBluetoothA2dpRoute 981fa6f70e225a7370c1ecb21ee7076c9086ecb9e9aSungsoo && sStatic.mBluetoothA2dpRoute != null && sStatic.isBluetoothA2dpOn()) { 98269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown selectRouteStatic(ROUTE_TYPE_ANY, sStatic.mBluetoothA2dpRoute, false); 98369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } else { 98469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown selectRouteStatic(ROUTE_TYPE_ANY, sStatic.mDefaultAudioVideo, false); 98569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 98669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 98769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 9889a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 989705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell * Compare the device address of a display and a route. 990705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell * Nulls/no device address will match another null/no address. 991705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell */ 992705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell static boolean matchesDeviceAddress(WifiDisplay display, RouteInfo info) { 993705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell final boolean routeHasAddress = info != null && info.mDeviceAddress != null; 994705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell if (display == null && !routeHasAddress) { 995705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell return true; 996705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 997705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 998705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell if (display != null && routeHasAddress) { 999705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell return display.getDeviceAddress().equals(info.mDeviceAddress); 1000705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1001705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell return false; 1002705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1003705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 1004705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell /** 10059a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Add an app-specified route for media to the MediaRouter. 10069a1de308cea2d160778fd977825f10a07b49d738Adam Powell * App-specified route definitions are created using {@link #createUserRoute(RouteCategory)} 10079a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 10089a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param info Definition of the route to add 10093afc18af2cea898753b10e8575dcf20c11356bcaJeff Brown * @see #createUserRoute(RouteCategory) 10109a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @see #removeUserRoute(UserRouteInfo) 10119a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 10129a1de308cea2d160778fd977825f10a07b49d738Adam Powell public void addUserRoute(UserRouteInfo info) { 10132ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell addRouteStatic(info); 10149a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 10159a1de308cea2d160778fd977825f10a07b49d738Adam Powell 1016d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell /** 1017d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell * @hide Framework use only 1018d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell */ 1019d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell public void addRouteInt(RouteInfo info) { 10202ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell addRouteStatic(info); 1021d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell } 1022d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell 10232ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell static void addRouteStatic(RouteInfo info) { 102418687b7a275b3782e63d52cdbe8ee9df191046e7Jae Seo Log.v(TAG, "Adding route: " + info); 10259a1de308cea2d160778fd977825f10a07b49d738Adam Powell final RouteCategory cat = info.getCategory(); 1026b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn if (!sStatic.mCategories.contains(cat)) { 1027b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn sStatic.mCategories.add(cat); 10289a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 1029d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell if (cat.isGroupable() && !(info instanceof RouteGroup)) { 10309a1de308cea2d160778fd977825f10a07b49d738Adam Powell // Enforce that any added route in a groupable category must be in a group. 10319a1de308cea2d160778fd977825f10a07b49d738Adam Powell final RouteGroup group = new RouteGroup(info.getCategory()); 1032dbbfa702a09f6d2d36dee1b552442d04a4673f89Adam Powell group.mSupportedTypes = info.mSupportedTypes; 1033b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn sStatic.mRoutes.add(group); 1034d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell dispatchRouteAdded(group); 1035b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell group.addRoute(info); 1036d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell 10379a1de308cea2d160778fd977825f10a07b49d738Adam Powell info = group; 1038d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell } else { 1039b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn sStatic.mRoutes.add(info); 1040d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell dispatchRouteAdded(info); 10419a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 10429a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 10439a1de308cea2d160778fd977825f10a07b49d738Adam Powell 10449a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 10459a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Remove an app-specified route for media from the MediaRouter. 10469a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 10479a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param info Definition of the route to remove 10489a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @see #addUserRoute(UserRouteInfo) 10499a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 10509a1de308cea2d160778fd977825f10a07b49d738Adam Powell public void removeUserRoute(UserRouteInfo info) { 105169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown removeRouteStatic(info); 10529a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 10539a1de308cea2d160778fd977825f10a07b49d738Adam Powell 1054690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell /** 1055690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell * Remove all app-specified routes from the MediaRouter. 1056690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell * 1057690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell * @see #removeUserRoute(UserRouteInfo) 1058690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell */ 1059690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell public void clearUserRoutes() { 1060b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn for (int i = 0; i < sStatic.mRoutes.size(); i++) { 1061b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn final RouteInfo info = sStatic.mRoutes.get(i); 1062d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell // TODO Right now, RouteGroups only ever contain user routes. 1063d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell // The code below will need to change if this assumption does. 1064d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell if (info instanceof UserRouteInfo || info instanceof RouteGroup) { 106569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown removeRouteStatic(info); 1066690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell i--; 1067690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell } 1068690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell } 1069690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell } 1070690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell 1071d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell /** 1072d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell * @hide internal use only 1073d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell */ 1074d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell public void removeRouteInt(RouteInfo info) { 107569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown removeRouteStatic(info); 1076d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell } 1077d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell 107869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown static void removeRouteStatic(RouteInfo info) { 107918687b7a275b3782e63d52cdbe8ee9df191046e7Jae Seo Log.v(TAG, "Removing route: " + info); 1080b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn if (sStatic.mRoutes.remove(info)) { 10819a1de308cea2d160778fd977825f10a07b49d738Adam Powell final RouteCategory removingCat = info.getCategory(); 1082b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn final int count = sStatic.mRoutes.size(); 10839a1de308cea2d160778fd977825f10a07b49d738Adam Powell boolean found = false; 10849a1de308cea2d160778fd977825f10a07b49d738Adam Powell for (int i = 0; i < count; i++) { 1085b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn final RouteCategory cat = sStatic.mRoutes.get(i).getCategory(); 10869a1de308cea2d160778fd977825f10a07b49d738Adam Powell if (removingCat == cat) { 10879a1de308cea2d160778fd977825f10a07b49d738Adam Powell found = true; 10889a1de308cea2d160778fd977825f10a07b49d738Adam Powell break; 10899a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 10909a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 10910abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown if (info.isSelected()) { 1092d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell // Removing the currently selected route? Select the default before we remove it. 109369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown selectDefaultRouteStatic(); 1094d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell } 1095690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell if (!found) { 1096b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn sStatic.mCategories.remove(removingCat); 1097690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell } 1098690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell dispatchRouteRemoved(info); 1099690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell } 1100690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell } 1101690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell 11029a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 11039a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Return the number of {@link MediaRouter.RouteCategory categories} currently 11049a1de308cea2d160778fd977825f10a07b49d738Adam Powell * represented by routes known to this MediaRouter. 11059a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 11069a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @return the number of unique categories represented by this MediaRouter's known routes 11079a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 11089a1de308cea2d160778fd977825f10a07b49d738Adam Powell public int getCategoryCount() { 1109b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn return sStatic.mCategories.size(); 11109a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 11119a1de308cea2d160778fd977825f10a07b49d738Adam Powell 11129a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 11139a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Return the {@link MediaRouter.RouteCategory category} at the given index. 11149a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Valid indices are in the range [0-getCategoryCount). 11159a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 11169a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param index which category to return 11179a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @return the category at index 11189a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 11199a1de308cea2d160778fd977825f10a07b49d738Adam Powell public RouteCategory getCategoryAt(int index) { 1120b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn return sStatic.mCategories.get(index); 11219a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 11229a1de308cea2d160778fd977825f10a07b49d738Adam Powell 11239a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 11249a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Return the number of {@link MediaRouter.RouteInfo routes} currently known 11259a1de308cea2d160778fd977825f10a07b49d738Adam Powell * to this MediaRouter. 11269a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 11279a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @return the number of routes tracked by this router 11289a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 11299a1de308cea2d160778fd977825f10a07b49d738Adam Powell public int getRouteCount() { 1130b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn return sStatic.mRoutes.size(); 11319a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 11329a1de308cea2d160778fd977825f10a07b49d738Adam Powell 11339a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 11349a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Return the route at the specified index. 11359a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 11369a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param index index of the route to return 11379a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @return the route at index 11389a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 11399a1de308cea2d160778fd977825f10a07b49d738Adam Powell public RouteInfo getRouteAt(int index) { 1140b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn return sStatic.mRoutes.get(index); 1141b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn } 1142b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn 1143b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn static int getRouteCountStatic() { 1144b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn return sStatic.mRoutes.size(); 1145b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn } 1146b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn 1147b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn static RouteInfo getRouteAtStatic(int index) { 1148b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn return sStatic.mRoutes.get(index); 11499a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 11509a1de308cea2d160778fd977825f10a07b49d738Adam Powell 11519a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 11529a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Create a new user route that may be modified and registered for use by the application. 11539a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 11549a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param category The category the new route will belong to 11559a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @return A new UserRouteInfo for use by the application 11569a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 11579a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @see #addUserRoute(UserRouteInfo) 11589a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @see #removeUserRoute(UserRouteInfo) 115969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * @see #createRouteCategory(CharSequence, boolean) 11609a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 11619a1de308cea2d160778fd977825f10a07b49d738Adam Powell public UserRouteInfo createUserRoute(RouteCategory category) { 11629a1de308cea2d160778fd977825f10a07b49d738Adam Powell return new UserRouteInfo(category); 11639a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 11649a1de308cea2d160778fd977825f10a07b49d738Adam Powell 11659a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 11669a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Create a new route category. Each route must belong to a category. 11679a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 11689a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param name Name of the new category 11699a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param isGroupable true if routes in this category may be grouped with one another 11709a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @return the new RouteCategory 11719a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 11729a1de308cea2d160778fd977825f10a07b49d738Adam Powell public RouteCategory createRouteCategory(CharSequence name, boolean isGroupable) { 11739a1de308cea2d160778fd977825f10a07b49d738Adam Powell return new RouteCategory(name, ROUTE_TYPE_USER, isGroupable); 11749a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 11755d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik 11760d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell /** 11770d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * Create a new route category. Each route must belong to a category. 11780d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * 11790d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * @param nameResId Resource ID of the name of the new category 11800d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * @param isGroupable true if routes in this category may be grouped with one another 11810d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * @return the new RouteCategory 11820d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell */ 11830d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public RouteCategory createRouteCategory(int nameResId, boolean isGroupable) { 11840d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell return new RouteCategory(nameResId, ROUTE_TYPE_USER, isGroupable); 11850d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell } 11869a1de308cea2d160778fd977825f10a07b49d738Adam Powell 118769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown /** 118869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * Rebinds the media router to handle routes that belong to the specified user. 118969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * Requires the interact across users permission to access the routes of another user. 119069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * <p> 119169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * This method is a complete hack to work around the singleton nature of the 119269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * media router when running inside of singleton processes like QuickSettings. 119369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * This mechanism should be burned to the ground when MediaRouter is redesigned. 119469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * Ideally the current user would be pulled from the Context but we need to break 119569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * down MediaRouter.Static before we can get there. 119669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * </p> 119769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * 119869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * @hide 119969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown */ 120069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public void rebindAsUser(int userId) { 120169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown sStatic.rebindAsUser(userId); 120269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 120369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 1204b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn static void updateRoute(final RouteInfo info) { 12059a1de308cea2d160778fd977825f10a07b49d738Adam Powell dispatchRouteChanged(info); 12069a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 12079a1de308cea2d160778fd977825f10a07b49d738Adam Powell 1208b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn static void dispatchRouteSelected(int type, RouteInfo info) { 120939d5c6172503620ac3761148adac5fd7fa20d02dAdam Powell for (CallbackInfo cbi : sStatic.mCallbacks) { 121066f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown if (cbi.filterRouteEvent(info)) { 1211b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn cbi.cb.onRouteSelected(cbi.router, type, info); 12129a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 12139a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 12149a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 12159a1de308cea2d160778fd977825f10a07b49d738Adam Powell 1216b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn static void dispatchRouteUnselected(int type, RouteInfo info) { 121739d5c6172503620ac3761148adac5fd7fa20d02dAdam Powell for (CallbackInfo cbi : sStatic.mCallbacks) { 121866f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown if (cbi.filterRouteEvent(info)) { 1219b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn cbi.cb.onRouteUnselected(cbi.router, type, info); 12209a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 12219a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 12229a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 12239a1de308cea2d160778fd977825f10a07b49d738Adam Powell 1224b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn static void dispatchRouteChanged(RouteInfo info) { 1225af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown dispatchRouteChanged(info, info.mSupportedTypes); 1226af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown } 1227af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown 1228af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown static void dispatchRouteChanged(RouteInfo info, int oldSupportedTypes) { 12294bad663518908c20ed4f93a27f46ffb09448497fSungsoo Lim if (DEBUG) { 12304bad663518908c20ed4f93a27f46ffb09448497fSungsoo Lim Log.d(TAG, "Dispatching route change: " + info); 12314bad663518908c20ed4f93a27f46ffb09448497fSungsoo Lim } 1232af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown final int newSupportedTypes = info.mSupportedTypes; 123339d5c6172503620ac3761148adac5fd7fa20d02dAdam Powell for (CallbackInfo cbi : sStatic.mCallbacks) { 1234af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown // Reconstruct some of the history for callbacks that may not have observed 1235af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown // all of the events needed to correctly interpret the current state. 1236af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown // FIXME: This is a strong signal that we should deprecate route type filtering 1237af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown // completely in the future because it can lead to inconsistencies in 1238af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown // applications. 1239af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown final boolean oldVisibility = cbi.filterRouteEvent(oldSupportedTypes); 1240af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown final boolean newVisibility = cbi.filterRouteEvent(newSupportedTypes); 1241af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown if (!oldVisibility && newVisibility) { 1242af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown cbi.cb.onRouteAdded(cbi.router, info); 1243af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown if (info.isSelected()) { 1244af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown cbi.cb.onRouteSelected(cbi.router, newSupportedTypes, info); 1245af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown } 1246af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown } 1247af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown if (oldVisibility || newVisibility) { 1248b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn cbi.cb.onRouteChanged(cbi.router, info); 12499a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 1250af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown if (oldVisibility && !newVisibility) { 1251af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown if (info.isSelected()) { 1252af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown cbi.cb.onRouteUnselected(cbi.router, oldSupportedTypes, info); 1253af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown } 1254af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown cbi.cb.onRouteRemoved(cbi.router, info); 1255af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown } 12569a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 12579a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 12589a1de308cea2d160778fd977825f10a07b49d738Adam Powell 1259b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn static void dispatchRouteAdded(RouteInfo info) { 126039d5c6172503620ac3761148adac5fd7fa20d02dAdam Powell for (CallbackInfo cbi : sStatic.mCallbacks) { 126166f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown if (cbi.filterRouteEvent(info)) { 1262b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn cbi.cb.onRouteAdded(cbi.router, info); 12639a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 12649a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 12659a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 12669a1de308cea2d160778fd977825f10a07b49d738Adam Powell 1267b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn static void dispatchRouteRemoved(RouteInfo info) { 126839d5c6172503620ac3761148adac5fd7fa20d02dAdam Powell for (CallbackInfo cbi : sStatic.mCallbacks) { 126966f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown if (cbi.filterRouteEvent(info)) { 1270b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn cbi.cb.onRouteRemoved(cbi.router, info); 12719a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 12729a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 12739a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 12749a1de308cea2d160778fd977825f10a07b49d738Adam Powell 1275b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn static void dispatchRouteGrouped(RouteInfo info, RouteGroup group, int index) { 127639d5c6172503620ac3761148adac5fd7fa20d02dAdam Powell for (CallbackInfo cbi : sStatic.mCallbacks) { 127766f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown if (cbi.filterRouteEvent(group)) { 1278b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn cbi.cb.onRouteGrouped(cbi.router, info, group, index); 1279d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell } 1280d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell } 1281d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell } 1282d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell 1283b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn static void dispatchRouteUngrouped(RouteInfo info, RouteGroup group) { 128439d5c6172503620ac3761148adac5fd7fa20d02dAdam Powell for (CallbackInfo cbi : sStatic.mCallbacks) { 128566f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown if (cbi.filterRouteEvent(group)) { 1286b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn cbi.cb.onRouteUngrouped(cbi.router, info, group); 12879a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 12889a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 12899a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 12909a1de308cea2d160778fd977825f10a07b49d738Adam Powell 12918e37a85bf3dc39519942698dc90a3951306b934bAdam Powell static void dispatchRouteVolumeChanged(RouteInfo info) { 12928e37a85bf3dc39519942698dc90a3951306b934bAdam Powell for (CallbackInfo cbi : sStatic.mCallbacks) { 129366f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown if (cbi.filterRouteEvent(info)) { 12948e37a85bf3dc39519942698dc90a3951306b934bAdam Powell cbi.cb.onRouteVolumeChanged(cbi.router, info); 12958e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 12968e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 12978e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 12988e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 129992130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown static void dispatchRoutePresentationDisplayChanged(RouteInfo info) { 130092130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown for (CallbackInfo cbi : sStatic.mCallbacks) { 130166f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown if (cbi.filterRouteEvent(info)) { 130292130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown cbi.cb.onRoutePresentationDisplayChanged(cbi.router, info); 130392130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown } 130492130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown } 130592130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown } 130692130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown 13078e37a85bf3dc39519942698dc90a3951306b934bAdam Powell static void systemVolumeChanged(int newValue) { 13088e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final RouteInfo selectedRoute = sStatic.mSelectedRoute; 13098e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (selectedRoute == null) return; 13108e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 13118e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (selectedRoute == sStatic.mBluetoothA2dpRoute || 1312705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell selectedRoute == sStatic.mDefaultAudioVideo) { 13138e37a85bf3dc39519942698dc90a3951306b934bAdam Powell dispatchRouteVolumeChanged(selectedRoute); 13148e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } else if (sStatic.mBluetoothA2dpRoute != null) { 1315fa6f70e225a7370c1ecb21ee7076c9086ecb9e9aSungsoo try { 1316fa6f70e225a7370c1ecb21ee7076c9086ecb9e9aSungsoo dispatchRouteVolumeChanged(sStatic.mAudioService.isBluetoothA2dpOn() ? 1317fa6f70e225a7370c1ecb21ee7076c9086ecb9e9aSungsoo sStatic.mBluetoothA2dpRoute : sStatic.mDefaultAudioVideo); 1318fa6f70e225a7370c1ecb21ee7076c9086ecb9e9aSungsoo } catch (RemoteException e) { 1319fa6f70e225a7370c1ecb21ee7076c9086ecb9e9aSungsoo Log.e(TAG, "Error checking Bluetooth A2DP state to report volume change", e); 1320fa6f70e225a7370c1ecb21ee7076c9086ecb9e9aSungsoo } 13218e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } else { 1322705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell dispatchRouteVolumeChanged(sStatic.mDefaultAudioVideo); 1323705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1324705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1325705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 132675af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown static void updateWifiDisplayStatus(WifiDisplayStatus status) { 132775af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown WifiDisplay[] displays; 1328615e413a90ff5898d8c458ebc9649ca95fa9fd98Adam Powell WifiDisplay activeDisplay; 132975af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown if (status.getFeatureState() == WifiDisplayStatus.FEATURE_STATE_ON) { 133075af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown displays = status.getDisplays(); 133175af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown activeDisplay = status.getActiveDisplay(); 1332af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown 1333af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown // Only the system is able to connect to wifi display routes. 1334af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown // The display manager will enforce this with a permission check but it 1335af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown // still publishes information about all available displays. 1336af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown // Filter the list down to just the active display. 1337af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown if (!sStatic.mCanConfigureWifiDisplays) { 1338af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown if (activeDisplay != null) { 1339af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown displays = new WifiDisplay[] { activeDisplay }; 1340af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown } else { 1341af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown displays = WifiDisplay.EMPTY_ARRAY; 1342af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown } 1343af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown } 1344615e413a90ff5898d8c458ebc9649ca95fa9fd98Adam Powell } else { 134575af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown displays = WifiDisplay.EMPTY_ARRAY; 1346615e413a90ff5898d8c458ebc9649ca95fa9fd98Adam Powell activeDisplay = null; 1347615e413a90ff5898d8c458ebc9649ca95fa9fd98Adam Powell } 1348ce468a35b388ca46578934706b38dbae94941643Jeff Brown String activeDisplayAddress = activeDisplay != null ? 1349ce468a35b388ca46578934706b38dbae94941643Jeff Brown activeDisplay.getDeviceAddress() : null; 1350705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 135175af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown // Add or update routes. 135275af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown for (int i = 0; i < displays.length; i++) { 135375af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown final WifiDisplay d = displays[i]; 135475af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown if (shouldShowWifiDisplay(d, activeDisplay)) { 1355ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang RouteInfo route = findWifiDisplayRoute(d); 1356ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang if (route == null) { 135775af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown route = makeWifiDisplayRoute(d, status); 1358ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang addRouteStatic(route); 1359ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang } else { 1360ce468a35b388ca46578934706b38dbae94941643Jeff Brown String address = d.getDeviceAddress(); 1361ce468a35b388ca46578934706b38dbae94941643Jeff Brown boolean disconnected = !address.equals(activeDisplayAddress) 1362ce468a35b388ca46578934706b38dbae94941643Jeff Brown && address.equals(sStatic.mPreviousActiveWifiDisplayAddress); 1363ce468a35b388ca46578934706b38dbae94941643Jeff Brown updateWifiDisplayRoute(route, d, status, disconnected); 1364ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang } 1365ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang if (d.equals(activeDisplay)) { 136669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown selectRouteStatic(route.getSupportedTypes(), route, false); 1367ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang } 13682ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell } 1369705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 137075af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown 137175af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown // Remove stale routes. 137275af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown for (int i = sStatic.mRoutes.size(); i-- > 0; ) { 137375af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown RouteInfo route = sStatic.mRoutes.get(i); 137475af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown if (route.mDeviceAddress != null) { 137575af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown WifiDisplay d = findWifiDisplay(displays, route.mDeviceAddress); 137675af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown if (d == null || !shouldShowWifiDisplay(d, activeDisplay)) { 137775af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown removeRouteStatic(route); 1378ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang } 1379705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1380705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1381ce468a35b388ca46578934706b38dbae94941643Jeff Brown 1382ce468a35b388ca46578934706b38dbae94941643Jeff Brown // Remember the current active wifi display address so that we can infer disconnections. 1383ce468a35b388ca46578934706b38dbae94941643Jeff Brown // TODO: This hack will go away once all of this is moved into the media router service. 1384ce468a35b388ca46578934706b38dbae94941643Jeff Brown sStatic.mPreviousActiveWifiDisplayAddress = activeDisplayAddress; 138575af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown } 1386705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 138775af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown private static boolean shouldShowWifiDisplay(WifiDisplay d, WifiDisplay activeDisplay) { 138875af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown return d.isRemembered() || d.equals(activeDisplay); 1389705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1390705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 1391ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang static int getWifiDisplayStatusCode(WifiDisplay d, WifiDisplayStatus wfdStatus) { 139269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown int newStatus; 1393ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang if (wfdStatus.getScanState() == WifiDisplayStatus.SCAN_STATE_SCANNING) { 1394ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang newStatus = RouteInfo.STATUS_SCANNING; 1395ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang } else if (d.isAvailable()) { 1396ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang newStatus = d.canConnect() ? 1397ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang RouteInfo.STATUS_AVAILABLE: RouteInfo.STATUS_IN_USE; 1398705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } else { 1399705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell newStatus = RouteInfo.STATUS_NOT_AVAILABLE; 1400705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1401705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 1402ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang if (d.equals(wfdStatus.getActiveDisplay())) { 1403ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang final int activeState = wfdStatus.getActiveDisplayState(); 1404705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell switch (activeState) { 1405705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell case WifiDisplayStatus.DISPLAY_STATE_CONNECTED: 140669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown newStatus = RouteInfo.STATUS_CONNECTED; 1407705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell break; 1408705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell case WifiDisplayStatus.DISPLAY_STATE_CONNECTING: 1409705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell newStatus = RouteInfo.STATUS_CONNECTING; 1410705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell break; 1411705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell case WifiDisplayStatus.DISPLAY_STATE_NOT_CONNECTED: 1412705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell Log.e(TAG, "Active display is not connected!"); 1413705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell break; 1414705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1415705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1416705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 1417ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang return newStatus; 1418ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang } 1419ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang 1420ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang static boolean isWifiDisplayEnabled(WifiDisplay d, WifiDisplayStatus wfdStatus) { 1421ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang return d.isAvailable() && (d.canConnect() || d.equals(wfdStatus.getActiveDisplay())); 1422ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang } 1423ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang 1424ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang static RouteInfo makeWifiDisplayRoute(WifiDisplay display, WifiDisplayStatus wfdStatus) { 1425ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang final RouteInfo newRoute = new RouteInfo(sStatic.mSystemCategory); 1426ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang newRoute.mDeviceAddress = display.getDeviceAddress(); 142769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown newRoute.mSupportedTypes = ROUTE_TYPE_LIVE_AUDIO | ROUTE_TYPE_LIVE_VIDEO 142869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown | ROUTE_TYPE_REMOTE_DISPLAY; 1429ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang newRoute.mVolumeHandling = RouteInfo.PLAYBACK_VOLUME_FIXED; 1430ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang newRoute.mPlaybackType = RouteInfo.PLAYBACK_TYPE_REMOTE; 1431ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang 143239ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown newRoute.setRealStatusCode(getWifiDisplayStatusCode(display, wfdStatus)); 1433ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang newRoute.mEnabled = isWifiDisplayEnabled(display, wfdStatus); 1434ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang newRoute.mName = display.getFriendlyDisplayName(); 1435ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang newRoute.mDescription = sStatic.mResources.getText( 1436ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang com.android.internal.R.string.wireless_display_route_description); 14375830b0b33618940d65197cec99d697b21908fec8Chong Zhang newRoute.updatePresentationDisplay(); 14389dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang newRoute.mDeviceType = RouteInfo.DEVICE_TYPE_TV; 1439ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang return newRoute; 1440ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang } 1441ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang 1442ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang private static void updateWifiDisplayRoute( 1443ce468a35b388ca46578934706b38dbae94941643Jeff Brown RouteInfo route, WifiDisplay display, WifiDisplayStatus wfdStatus, 1444ce468a35b388ca46578934706b38dbae94941643Jeff Brown boolean disconnected) { 1445ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang boolean changed = false; 14462444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown final String newName = display.getFriendlyDisplayName(); 14472444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown if (!route.getName().equals(newName)) { 1448705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell route.mName = newName; 1449705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell changed = true; 1450705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1451705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 1452ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang boolean enabled = isWifiDisplayEnabled(display, wfdStatus); 1453ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang changed |= route.mEnabled != enabled; 1454ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang route.mEnabled = enabled; 1455705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 145639ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown changed |= route.setRealStatusCode(getWifiDisplayStatusCode(display, wfdStatus)); 1457705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 1458705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell if (changed) { 1459705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell dispatchRouteChanged(route); 1460705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1461705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 1462ce468a35b388ca46578934706b38dbae94941643Jeff Brown if ((!enabled || disconnected) && route.isSelected()) { 1463705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell // Oops, no longer available. Reselect the default. 146469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown selectDefaultRouteStatic(); 1465705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1466705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1467705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 146875af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown private static WifiDisplay findWifiDisplay(WifiDisplay[] displays, String deviceAddress) { 1469705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell for (int i = 0; i < displays.length; i++) { 147075af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown final WifiDisplay d = displays[i]; 147175af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown if (d.getDeviceAddress().equals(deviceAddress)) { 147275af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown return d; 1473705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1474705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1475705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell return null; 1476705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1477705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 1478705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell private static RouteInfo findWifiDisplayRoute(WifiDisplay d) { 1479705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell final int count = sStatic.mRoutes.size(); 1480705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell for (int i = 0; i < count; i++) { 1481705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell final RouteInfo info = sStatic.mRoutes.get(i); 1482705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell if (d.getDeviceAddress().equals(info.mDeviceAddress)) { 1483705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell return info; 1484705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1485705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1486705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell return null; 14878e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 14888e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 14899a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 14909a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Information about a media route. 14919a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 1492b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn public static class RouteInfo { 14939a1de308cea2d160778fd977825f10a07b49d738Adam Powell CharSequence mName; 14940d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell int mNameResId; 149556d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown CharSequence mDescription; 14969a1de308cea2d160778fd977825f10a07b49d738Adam Powell private CharSequence mStatus; 14979a1de308cea2d160778fd977825f10a07b49d738Adam Powell int mSupportedTypes; 14989dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang int mDeviceType; 14999a1de308cea2d160778fd977825f10a07b49d738Adam Powell RouteGroup mGroup; 15009a1de308cea2d160778fd977825f10a07b49d738Adam Powell final RouteCategory mCategory; 1501ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell Drawable mIcon; 15021357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi // playback information 15031357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi int mPlaybackType = PLAYBACK_TYPE_LOCAL; 15041357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi int mVolumeMax = RemoteControlClient.DEFAULT_PLAYBACK_VOLUME; 15051357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi int mVolume = RemoteControlClient.DEFAULT_PLAYBACK_VOLUME; 15061357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi int mVolumeHandling = RemoteControlClient.DEFAULT_PLAYBACK_VOLUME_HANDLING; 15071357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi int mPlaybackStream = AudioManager.STREAM_MUSIC; 15081357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi VolumeCallbackInfo mVcb; 150992130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown Display mPresentationDisplay; 15105830b0b33618940d65197cec99d697b21908fec8Chong Zhang int mPresentationDisplayId = -1; 15119a1de308cea2d160778fd977825f10a07b49d738Adam Powell 1512705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell String mDeviceAddress; 1513705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell boolean mEnabled = true; 1514705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 151569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // An id by which the route is known to the media router service. 151669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Null if this route only exists as an artifact within this process. 151769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown String mGlobalRouteId; 151869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 1519705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell // A predetermined connection status that can override mStatus 152039ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown private int mRealStatusCode; 152139ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown private int mResolvedStatusCode; 1522705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 15232ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell /** @hide */ public static final int STATUS_NONE = 0; 15242ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell /** @hide */ public static final int STATUS_SCANNING = 1; 15252ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell /** @hide */ public static final int STATUS_CONNECTING = 2; 15262ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell /** @hide */ public static final int STATUS_AVAILABLE = 3; 15272ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell /** @hide */ public static final int STATUS_NOT_AVAILABLE = 4; 1528ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang /** @hide */ public static final int STATUS_IN_USE = 5; 152969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown /** @hide */ public static final int STATUS_CONNECTED = 6; 1530705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 15319dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang /** @hide */ 15329dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang @IntDef({DEVICE_TYPE_UNKNOWN, DEVICE_TYPE_TV, DEVICE_TYPE_SPEAKER, DEVICE_TYPE_BLUETOOTH}) 15339dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang @Retention(RetentionPolicy.SOURCE) 15349dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang public @interface DeviceType {} 15359dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang 15369dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang /** 15379dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang * The default receiver device type of the route indicating the type is unknown. 15389dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang * 15399dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang * @see #getDeviceType 15409dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang */ 15419dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang public static final int DEVICE_TYPE_UNKNOWN = 0; 15429dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang 15439dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang /** 15449dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang * A receiver device type of the route indicating the presentation of the media is happening 15459dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang * on a TV. 15469dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang * 15479dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang * @see #getDeviceType 15489dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang */ 15499dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang public static final int DEVICE_TYPE_TV = 1; 15509dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang 15519dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang /** 15529dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang * A receiver device type of the route indicating the presentation of the media is happening 15539dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang * on a speaker. 15549dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang * 15559dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang * @see #getDeviceType 15569dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang */ 15579dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang public static final int DEVICE_TYPE_SPEAKER = 2; 15589dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang 15599dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang /** 15609dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang * A receiver device type of the route indicating the presentation of the media is happening 15619dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang * on a bluetooth device such as a bluetooth speaker. 15629dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang * 15639dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang * @see #getDeviceType 15649dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang */ 15659dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang public static final int DEVICE_TYPE_BLUETOOTH = 3; 15669dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang 1567b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell private Object mTag; 1568b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell 15697c090d54e2c0eb5309d3f7dc131e137d9c986793Insun Kang /** @hide */ 15707c090d54e2c0eb5309d3f7dc131e137d9c986793Insun Kang @IntDef({PLAYBACK_TYPE_LOCAL, PLAYBACK_TYPE_REMOTE}) 15717c090d54e2c0eb5309d3f7dc131e137d9c986793Insun Kang @Retention(RetentionPolicy.SOURCE) 15727c090d54e2c0eb5309d3f7dc131e137d9c986793Insun Kang public @interface PlaybackType {} 15737c090d54e2c0eb5309d3f7dc131e137d9c986793Insun Kang 15741357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 15751357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * The default playback type, "local", indicating the presentation of the media is happening 1576bc4cf00dc5bf6e0e3c01206d5c46e64306df260aJohn Spurlock * on the same device (e.g. a phone, a tablet) as where it is controlled from. 157769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * @see #getPlaybackType() 15781357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 15791357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public final static int PLAYBACK_TYPE_LOCAL = 0; 15807c090d54e2c0eb5309d3f7dc131e137d9c986793Insun Kang 15811357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 15821357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * A playback type indicating the presentation of the media is happening on 1583bc4cf00dc5bf6e0e3c01206d5c46e64306df260aJohn Spurlock * a different device (i.e. the remote device) than where it is controlled from. 158469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * @see #getPlaybackType() 15851357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 15861357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public final static int PLAYBACK_TYPE_REMOTE = 1; 15877c090d54e2c0eb5309d3f7dc131e137d9c986793Insun Kang 15887c090d54e2c0eb5309d3f7dc131e137d9c986793Insun Kang /** @hide */ 15897c090d54e2c0eb5309d3f7dc131e137d9c986793Insun Kang @IntDef({PLAYBACK_VOLUME_FIXED,PLAYBACK_VOLUME_VARIABLE}) 15907c090d54e2c0eb5309d3f7dc131e137d9c986793Insun Kang @Retention(RetentionPolicy.SOURCE) 15917c090d54e2c0eb5309d3f7dc131e137d9c986793Insun Kang private @interface PlaybackVolume {} 15927c090d54e2c0eb5309d3f7dc131e137d9c986793Insun Kang 15931357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 1594bc4cf00dc5bf6e0e3c01206d5c46e64306df260aJohn Spurlock * Playback information indicating the playback volume is fixed, i.e. it cannot be 15951357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * controlled from this object. An example of fixed playback volume is a remote player, 15961357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * playing over HDMI where the user prefers to control the volume on the HDMI sink, rather 15971357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * than attenuate at the source. 159869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * @see #getVolumeHandling() 15991357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 16001357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public final static int PLAYBACK_VOLUME_FIXED = 0; 16011357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 16021357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * Playback information indicating the playback volume is variable and can be controlled 16031357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * from this object. 160469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * @see #getVolumeHandling() 16051357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 16061357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public final static int PLAYBACK_VOLUME_VARIABLE = 1; 16071357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 16089a1de308cea2d160778fd977825f10a07b49d738Adam Powell RouteInfo(RouteCategory category) { 16099a1de308cea2d160778fd977825f10a07b49d738Adam Powell mCategory = category; 16109dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang mDeviceType = DEVICE_TYPE_UNKNOWN; 16119a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 16129a1de308cea2d160778fd977825f10a07b49d738Adam Powell 16139a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 161456d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * Gets the user-visible name of the route. 161556d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * <p> 161656d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * The route name identifies the destination represented by the route. 161756d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * It may be a user-supplied name, an alias, or device serial number. 161856d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * </p> 161956d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * 162056d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * @return The user-visible name of a media route. This is the string presented 16219a1de308cea2d160778fd977825f10a07b49d738Adam Powell * to users who may select this as the active route. 16229a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 16239a1de308cea2d160778fd977825f10a07b49d738Adam Powell public CharSequence getName() { 16240d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell return getName(sStatic.mResources); 16250d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell } 162656d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown 16270d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell /** 162856d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * Return the properly localized/resource user-visible name of this route. 162956d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * <p> 163056d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * The route name identifies the destination represented by the route. 163156d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * It may be a user-supplied name, an alias, or device serial number. 163256d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * </p> 163356d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * 16340d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * @param context Context used to resolve the correct configuration to load 163556d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * @return The user-visible name of a media route. This is the string presented 16360d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * to users who may select this as the active route. 16370d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell */ 16380d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public CharSequence getName(Context context) { 16390d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell return getName(context.getResources()); 16400d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell } 164156d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown 16420d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell CharSequence getName(Resources res) { 16430d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell if (mNameResId != 0) { 1644eadd6d2329972129c96dee390a8b786b37313d17Hyundo Moon return res.getText(mNameResId); 16450d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell } 16469a1de308cea2d160778fd977825f10a07b49d738Adam Powell return mName; 16479a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 16489a1de308cea2d160778fd977825f10a07b49d738Adam Powell 16499a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 165056d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * Gets the user-visible description of the route. 165156d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * <p> 165256d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * The route description describes the kind of destination represented by the route. 165356d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * It may be a user-supplied string, a model number or brand of device. 165456d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * </p> 165556d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * 165656d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * @return The description of the route, or null if none. 165756d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown */ 165856d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown public CharSequence getDescription() { 165956d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown return mDescription; 166056d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown } 166156d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown 166256d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown /** 166356d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * @return The user-visible status for a media route. This may include a description 16649a1de308cea2d160778fd977825f10a07b49d738Adam Powell * of the currently playing media, if available. 16659a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 16669a1de308cea2d160778fd977825f10a07b49d738Adam Powell public CharSequence getStatus() { 16679a1de308cea2d160778fd977825f10a07b49d738Adam Powell return mStatus; 16689a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 16699a1de308cea2d160778fd977825f10a07b49d738Adam Powell 16709a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 1671705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell * Set this route's status by predetermined status code. If the caller 1672705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell * should dispatch a route changed event this call will return true; 1673705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell */ 167439ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown boolean setRealStatusCode(int statusCode) { 167539ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown if (mRealStatusCode != statusCode) { 167639ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown mRealStatusCode = statusCode; 167739ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown return resolveStatusCode(); 167839ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown } 167939ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown return false; 168039ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown } 168139ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown 168239ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown /** 168339ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown * Resolves the status code whenever the real status code or selection state 168439ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown * changes. 168539ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown */ 168639ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown boolean resolveStatusCode() { 168739ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown int statusCode = mRealStatusCode; 168839ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown if (isSelected()) { 1689705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell switch (statusCode) { 169039ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown // If the route is selected and its status appears to be between states 169139ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown // then report it as connecting even though it has not yet had a chance 169239ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown // to officially move into the CONNECTING state. Note that routes in 169339ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown // the NONE state are assumed to not require an explicit connection 169439ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown // lifecycle whereas those that are AVAILABLE are assumed to have 169539ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown // to eventually proceed to CONNECTED. 1696705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell case STATUS_AVAILABLE: 169739ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown case STATUS_SCANNING: 169839ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown statusCode = STATUS_CONNECTING; 169969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown break; 1700705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1701705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 170239ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown if (mResolvedStatusCode == statusCode) { 170339ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown return false; 170439ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown } 170539ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown 170639ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown mResolvedStatusCode = statusCode; 170739ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown int resId; 170839ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown switch (statusCode) { 170939ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown case STATUS_SCANNING: 171039ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown resId = com.android.internal.R.string.media_route_status_scanning; 171139ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown break; 171239ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown case STATUS_CONNECTING: 171339ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown resId = com.android.internal.R.string.media_route_status_connecting; 171439ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown break; 171539ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown case STATUS_AVAILABLE: 171639ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown resId = com.android.internal.R.string.media_route_status_available; 171739ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown break; 171839ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown case STATUS_NOT_AVAILABLE: 171939ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown resId = com.android.internal.R.string.media_route_status_not_available; 172039ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown break; 172139ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown case STATUS_IN_USE: 172239ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown resId = com.android.internal.R.string.media_route_status_in_use; 172339ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown break; 172439ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown case STATUS_CONNECTED: 172539ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown case STATUS_NONE: 172639ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown default: 172739ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown resId = 0; 172839ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown break; 172939ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown } 173039ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown mStatus = resId != 0 ? sStatic.mResources.getText(resId) : null; 173139ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown return true; 1732705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 1733705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 1734705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell /** 17352ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell * @hide 17362ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell */ 17372ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell public int getStatusCode() { 173839ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown return mResolvedStatusCode; 17392ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell } 17402ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell 17412ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell /** 17429a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @return A media type flag set describing which types this route supports. 17439a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 17449a1de308cea2d160778fd977825f10a07b49d738Adam Powell public int getSupportedTypes() { 17459a1de308cea2d160778fd977825f10a07b49d738Adam Powell return mSupportedTypes; 17469a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 17479a1de308cea2d160778fd977825f10a07b49d738Adam Powell 17489dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang /** 17499dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang * Gets the type of the receiver device associated with this route. 17509dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang * 17519dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang * @return The type of the receiver device associated with this route: 17529dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang * {@link #DEVICE_TYPE_BLUETOOTH}, {@link #DEVICE_TYPE_TV}, {@link #DEVICE_TYPE_SPEAKER}, 17539dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang * or {@link #DEVICE_TYPE_UNKNOWN}. 17549dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang */ 17559dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang @DeviceType 17569dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang public int getDeviceType() { 17579dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang return mDeviceType; 17589dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang } 17599dd66417ea984e4ff809ecdba78e3f55a8a17467Insun Kang 17600abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown /** @hide */ 17610abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown public boolean matchesTypes(int types) { 17620abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown return (mSupportedTypes & types) != 0; 17630abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown } 17640abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown 17659a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 17669a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @return The group that this route belongs to. 17679a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 17689a1de308cea2d160778fd977825f10a07b49d738Adam Powell public RouteGroup getGroup() { 17699a1de308cea2d160778fd977825f10a07b49d738Adam Powell return mGroup; 17709a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 17719a1de308cea2d160778fd977825f10a07b49d738Adam Powell 17729a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 17739a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @return the category this route belongs to. 17749a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 17759a1de308cea2d160778fd977825f10a07b49d738Adam Powell public RouteCategory getCategory() { 17769a1de308cea2d160778fd977825f10a07b49d738Adam Powell return mCategory; 17779a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 17789a1de308cea2d160778fd977825f10a07b49d738Adam Powell 1779ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell /** 1780ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * Get the icon representing this route. 1781ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * This icon will be used in picker UIs if available. 1782ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * 1783ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * @return the icon representing this route or null if no icon is available 1784ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell */ 1785ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell public Drawable getIconDrawable() { 1786ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell return mIcon; 1787ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell } 1788ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell 1789b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell /** 1790b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell * Set an application-specific tag object for this route. 1791b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell * The application may use this to store arbitrary data associated with the 1792b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell * route for internal tracking. 1793b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell * 1794b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell * <p>Note that the lifespan of a route may be well past the lifespan of 1795b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell * an Activity or other Context; take care that objects you store here 1796b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell * will not keep more data in memory alive than you intend.</p> 1797b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell * 1798b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell * @param tag Arbitrary, app-specific data for this route to hold for later use 1799b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell */ 1800b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell public void setTag(Object tag) { 1801b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell mTag = tag; 1802130b4572d1f3df702e5b296a655d15a41f6d4c66Adam Powell routeUpdated(); 1803b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell } 1804b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell 1805b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell /** 1806b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell * @return The tag object previously set by the application 1807b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell * @see #setTag(Object) 1808b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell */ 1809b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell public Object getTag() { 1810b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell return mTag; 1811b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell } 1812b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell 18131357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 18141357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @return the type of playback associated with this route 18151357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @see UserRouteInfo#setPlaybackType(int) 18161357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 18177c090d54e2c0eb5309d3f7dc131e137d9c986793Insun Kang @PlaybackType 18181357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public int getPlaybackType() { 18191357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi return mPlaybackType; 18201357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 18211357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 18221357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 18231357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @return the stream over which the playback associated with this route is performed 18241357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @see UserRouteInfo#setPlaybackStream(int) 18251357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 18261357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public int getPlaybackStream() { 18271357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi return mPlaybackStream; 18281357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 18291357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 18301357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 18318e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * Return the current volume for this route. Depending on the route, this may only 18328e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * be valid if the route is currently selected. 18338e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * 18341357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @return the volume at which the playback associated with this route is performed 18351357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @see UserRouteInfo#setVolume(int) 18361357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 18371357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public int getVolume() { 18381357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi if (mPlaybackType == PLAYBACK_TYPE_LOCAL) { 18391357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi int vol = 0; 18401357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi try { 18411357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi vol = sStatic.mAudioService.getStreamVolume(mPlaybackStream); 18421357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } catch (RemoteException e) { 18431357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi Log.e(TAG, "Error getting local stream volume", e); 18441357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 18451357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi return vol; 18461357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } else { 18471357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi return mVolume; 18481357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 18491357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 18501357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 18511357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 18528e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * Request a volume change for this route. 18538e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * @param volume value between 0 and getVolumeMax 18548e37a85bf3dc39519942698dc90a3951306b934bAdam Powell */ 18558e37a85bf3dc39519942698dc90a3951306b934bAdam Powell public void requestSetVolume(int volume) { 18568e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (mPlaybackType == PLAYBACK_TYPE_LOCAL) { 18578e37a85bf3dc39519942698dc90a3951306b934bAdam Powell try { 1858ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn sStatic.mAudioService.setStreamVolume(mPlaybackStream, volume, 0, 1859ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn ActivityThread.currentPackageName()); 18608e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } catch (RemoteException e) { 18618e37a85bf3dc39519942698dc90a3951306b934bAdam Powell Log.e(TAG, "Error setting local stream volume", e); 18628e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 18638e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } else { 186469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown sStatic.requestSetVolume(this, volume); 18658e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 18668e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 18678e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 18688e37a85bf3dc39519942698dc90a3951306b934bAdam Powell /** 18698e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * Request an incremental volume update for this route. 18708e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * @param direction Delta to apply to the current volume 18718e37a85bf3dc39519942698dc90a3951306b934bAdam Powell */ 18728e37a85bf3dc39519942698dc90a3951306b934bAdam Powell public void requestUpdateVolume(int direction) { 18738e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (mPlaybackType == PLAYBACK_TYPE_LOCAL) { 18748e37a85bf3dc39519942698dc90a3951306b934bAdam Powell try { 18758e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final int volume = 18768e37a85bf3dc39519942698dc90a3951306b934bAdam Powell Math.max(0, Math.min(getVolume() + direction, getVolumeMax())); 1877ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn sStatic.mAudioService.setStreamVolume(mPlaybackStream, volume, 0, 1878ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn ActivityThread.currentPackageName()); 18798e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } catch (RemoteException e) { 18808e37a85bf3dc39519942698dc90a3951306b934bAdam Powell Log.e(TAG, "Error setting local stream volume", e); 18818e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 18828e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } else { 188369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown sStatic.requestUpdateVolume(this, direction); 18848e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 18858e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 18868e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 18878e37a85bf3dc39519942698dc90a3951306b934bAdam Powell /** 18881357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @return the maximum volume at which the playback associated with this route is performed 18891357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @see UserRouteInfo#setVolumeMax(int) 18901357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 18911357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public int getVolumeMax() { 18921357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi if (mPlaybackType == PLAYBACK_TYPE_LOCAL) { 18931357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi int volMax = 0; 18941357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi try { 18951357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi volMax = sStatic.mAudioService.getStreamMaxVolume(mPlaybackStream); 18961357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } catch (RemoteException e) { 18971357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi Log.e(TAG, "Error getting local stream volume", e); 18981357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 18991357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi return volMax; 19001357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } else { 19011357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi return mVolumeMax; 19021357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 19031357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 19041357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 19051357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 19061357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @return how volume is handling on the route 19071357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @see UserRouteInfo#setVolumeHandling(int) 19081357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 19097c090d54e2c0eb5309d3f7dc131e137d9c986793Insun Kang @PlaybackVolume 19101357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public int getVolumeHandling() { 19111357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi return mVolumeHandling; 19121357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 19131357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 1914705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell /** 191592130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * Gets the {@link Display} that should be used by the application to show 191692130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * a {@link android.app.Presentation} on an external display when this route is selected. 191792130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * Depending on the route, this may only be valid if the route is currently 191892130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * selected. 191992130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * <p> 192092130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * The preferred presentation display may change independently of the route 192192130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * being selected or unselected. For example, the presentation display 192292130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * of the default system route may change when an external HDMI display is connected 192392130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * or disconnected even though the route itself has not changed. 192492130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * </p><p> 192592130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * This method may return null if there is no external display associated with 192692130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * the route or if the display is not ready to show UI yet. 192792130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * </p><p> 192892130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * The application should listen for changes to the presentation display 192992130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * using the {@link Callback#onRoutePresentationDisplayChanged} callback and 193092130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * show or dismiss its {@link android.app.Presentation} accordingly when the display 193192130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * becomes available or is removed. 193292130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * </p><p> 193392130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * This method only makes sense for {@link #ROUTE_TYPE_LIVE_VIDEO live video} routes. 193492130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * </p> 193592130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * 193692130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * @return The preferred presentation display to use when this route is 193792130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * selected or null if none. 193892130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * 193992130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * @see #ROUTE_TYPE_LIVE_VIDEO 194092130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * @see android.app.Presentation 194192130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown */ 194292130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown public Display getPresentationDisplay() { 194392130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown return mPresentationDisplay; 194492130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown } 194592130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown 19465830b0b33618940d65197cec99d697b21908fec8Chong Zhang boolean updatePresentationDisplay() { 19475830b0b33618940d65197cec99d697b21908fec8Chong Zhang Display display = choosePresentationDisplay(); 19485830b0b33618940d65197cec99d697b21908fec8Chong Zhang if (mPresentationDisplay != display) { 19495830b0b33618940d65197cec99d697b21908fec8Chong Zhang mPresentationDisplay = display; 19505830b0b33618940d65197cec99d697b21908fec8Chong Zhang return true; 19515830b0b33618940d65197cec99d697b21908fec8Chong Zhang } 19525830b0b33618940d65197cec99d697b21908fec8Chong Zhang return false; 19535830b0b33618940d65197cec99d697b21908fec8Chong Zhang } 19545830b0b33618940d65197cec99d697b21908fec8Chong Zhang 19555830b0b33618940d65197cec99d697b21908fec8Chong Zhang private Display choosePresentationDisplay() { 19565830b0b33618940d65197cec99d697b21908fec8Chong Zhang if ((mSupportedTypes & ROUTE_TYPE_LIVE_VIDEO) != 0) { 19575830b0b33618940d65197cec99d697b21908fec8Chong Zhang Display[] displays = sStatic.getAllPresentationDisplays(); 19585830b0b33618940d65197cec99d697b21908fec8Chong Zhang 19595830b0b33618940d65197cec99d697b21908fec8Chong Zhang // Ensure that the specified display is valid for presentations. 19605830b0b33618940d65197cec99d697b21908fec8Chong Zhang // This check will normally disallow the default display unless it was 19615830b0b33618940d65197cec99d697b21908fec8Chong Zhang // configured as a presentation display for some reason. 19625830b0b33618940d65197cec99d697b21908fec8Chong Zhang if (mPresentationDisplayId >= 0) { 19635830b0b33618940d65197cec99d697b21908fec8Chong Zhang for (Display display : displays) { 19645830b0b33618940d65197cec99d697b21908fec8Chong Zhang if (display.getDisplayId() == mPresentationDisplayId) { 19655830b0b33618940d65197cec99d697b21908fec8Chong Zhang return display; 19665830b0b33618940d65197cec99d697b21908fec8Chong Zhang } 19675830b0b33618940d65197cec99d697b21908fec8Chong Zhang } 19685830b0b33618940d65197cec99d697b21908fec8Chong Zhang return null; 19695830b0b33618940d65197cec99d697b21908fec8Chong Zhang } 19705830b0b33618940d65197cec99d697b21908fec8Chong Zhang 19715830b0b33618940d65197cec99d697b21908fec8Chong Zhang // Find the indicated Wifi display by its address. 19725830b0b33618940d65197cec99d697b21908fec8Chong Zhang if (mDeviceAddress != null) { 19735830b0b33618940d65197cec99d697b21908fec8Chong Zhang for (Display display : displays) { 19745830b0b33618940d65197cec99d697b21908fec8Chong Zhang if (display.getType() == Display.TYPE_WIFI 19755830b0b33618940d65197cec99d697b21908fec8Chong Zhang && mDeviceAddress.equals(display.getAddress())) { 19765830b0b33618940d65197cec99d697b21908fec8Chong Zhang return display; 19775830b0b33618940d65197cec99d697b21908fec8Chong Zhang } 19785830b0b33618940d65197cec99d697b21908fec8Chong Zhang } 19795830b0b33618940d65197cec99d697b21908fec8Chong Zhang return null; 19805830b0b33618940d65197cec99d697b21908fec8Chong Zhang } 19815830b0b33618940d65197cec99d697b21908fec8Chong Zhang 19825830b0b33618940d65197cec99d697b21908fec8Chong Zhang // For the default route, choose the first presentation display from the list. 19835830b0b33618940d65197cec99d697b21908fec8Chong Zhang if (this == sStatic.mDefaultAudioVideo && displays.length > 0) { 19845830b0b33618940d65197cec99d697b21908fec8Chong Zhang return displays[0]; 19855830b0b33618940d65197cec99d697b21908fec8Chong Zhang } 19865830b0b33618940d65197cec99d697b21908fec8Chong Zhang } 19875830b0b33618940d65197cec99d697b21908fec8Chong Zhang return null; 19885830b0b33618940d65197cec99d697b21908fec8Chong Zhang } 19895830b0b33618940d65197cec99d697b21908fec8Chong Zhang 199075af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown /** @hide */ 199175af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown public String getDeviceAddress() { 199275af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown return mDeviceAddress; 199375af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown } 199475af171006ee80aaf7cfb56ded1378afe0084ccaJeff Brown 199592130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown /** 1996a27b8fb4296c1271ddf5916843ddffda6764e65fJeff Brown * Returns true if this route is enabled and may be selected. 1997a27b8fb4296c1271ddf5916843ddffda6764e65fJeff Brown * 1998a27b8fb4296c1271ddf5916843ddffda6764e65fJeff Brown * @return True if this route is enabled. 1999705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell */ 2000705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell public boolean isEnabled() { 2001705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell return mEnabled; 2002705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 2003705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 2004a27b8fb4296c1271ddf5916843ddffda6764e65fJeff Brown /** 2005a27b8fb4296c1271ddf5916843ddffda6764e65fJeff Brown * Returns true if the route is in the process of connecting and is not 2006a27b8fb4296c1271ddf5916843ddffda6764e65fJeff Brown * yet ready for use. 2007a27b8fb4296c1271ddf5916843ddffda6764e65fJeff Brown * 2008a27b8fb4296c1271ddf5916843ddffda6764e65fJeff Brown * @return True if this route is in the process of connecting. 2009a27b8fb4296c1271ddf5916843ddffda6764e65fJeff Brown */ 2010a27b8fb4296c1271ddf5916843ddffda6764e65fJeff Brown public boolean isConnecting() { 201139ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown return mResolvedStatusCode == STATUS_CONNECTING; 20120abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown } 20130abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown 20140abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown /** @hide */ 20150abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown public boolean isSelected() { 20160abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown return this == sStatic.mSelectedRoute; 20170abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown } 20180abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown 20190abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown /** @hide */ 20200abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown public boolean isDefault() { 20210abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown return this == sStatic.mDefaultAudioVideo; 20220abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown } 20230abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown 20240abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown /** @hide */ 20250abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown public void select() { 20260abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown selectRouteStatic(mSupportedTypes, this, true); 2027a27b8fb4296c1271ddf5916843ddffda6764e65fJeff Brown } 2028a27b8fb4296c1271ddf5916843ddffda6764e65fJeff Brown 20299a1de308cea2d160778fd977825f10a07b49d738Adam Powell void setStatusInt(CharSequence status) { 20309a1de308cea2d160778fd977825f10a07b49d738Adam Powell if (!status.equals(mStatus)) { 20319a1de308cea2d160778fd977825f10a07b49d738Adam Powell mStatus = status; 20329a1de308cea2d160778fd977825f10a07b49d738Adam Powell if (mGroup != null) { 20339a1de308cea2d160778fd977825f10a07b49d738Adam Powell mGroup.memberStatusChanged(this, status); 20349a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 20359a1de308cea2d160778fd977825f10a07b49d738Adam Powell routeUpdated(); 20369a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 20379a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 20389a1de308cea2d160778fd977825f10a07b49d738Adam Powell 20391357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi final IRemoteVolumeObserver.Stub mRemoteVolObserver = new IRemoteVolumeObserver.Stub() { 204069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown @Override 20411357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public void dispatchRemoteVolumeUpdate(final int direction, final int value) { 20421357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi sStatic.mHandler.post(new Runnable() { 20431357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi @Override 20441357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public void run() { 20451357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi if (mVcb != null) { 20461357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi if (direction != 0) { 20471357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi mVcb.vcb.onVolumeUpdateRequest(mVcb.route, direction); 20481357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } else { 20491357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi mVcb.vcb.onVolumeSetRequest(mVcb.route, value); 20501357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 20511357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 20521357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 20531357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi }); 20541357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 20551357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi }; 20561357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 20579a1de308cea2d160778fd977825f10a07b49d738Adam Powell void routeUpdated() { 20589a1de308cea2d160778fd977825f10a07b49d738Adam Powell updateRoute(this); 20599a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 20609a1de308cea2d160778fd977825f10a07b49d738Adam Powell 20619a1de308cea2d160778fd977825f10a07b49d738Adam Powell @Override 20629a1de308cea2d160778fd977825f10a07b49d738Adam Powell public String toString() { 2063d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell String supportedTypes = typesToString(getSupportedTypes()); 206492130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown return getClass().getSimpleName() + "{ name=" + getName() + 206556d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown ", description=" + getDescription() + 206692130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown ", status=" + getStatus() + 206792130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown ", category=" + getCategory() + 206892130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown ", supportedTypes=" + supportedTypes + 206969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown ", presentationDisplay=" + mPresentationDisplay + " }"; 20709a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 20719a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 20729a1de308cea2d160778fd977825f10a07b49d738Adam Powell 20739a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 20749a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Information about a route that the application may define and modify. 20758e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * A user route defaults to {@link RouteInfo#PLAYBACK_TYPE_REMOTE} and 20768e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * {@link RouteInfo#PLAYBACK_VOLUME_FIXED}. 20779a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 20789a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @see MediaRouter.RouteInfo 20799a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 2080b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn public static class UserRouteInfo extends RouteInfo { 2081ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell RemoteControlClient mRcc; 20825d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik SessionVolumeProvider mSvp; 20839a1de308cea2d160778fd977825f10a07b49d738Adam Powell 20849a1de308cea2d160778fd977825f10a07b49d738Adam Powell UserRouteInfo(RouteCategory category) { 20859a1de308cea2d160778fd977825f10a07b49d738Adam Powell super(category); 20869a1de308cea2d160778fd977825f10a07b49d738Adam Powell mSupportedTypes = ROUTE_TYPE_USER; 20878e37a85bf3dc39519942698dc90a3951306b934bAdam Powell mPlaybackType = PLAYBACK_TYPE_REMOTE; 20888e37a85bf3dc39519942698dc90a3951306b934bAdam Powell mVolumeHandling = PLAYBACK_VOLUME_FIXED; 20899a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 20909a1de308cea2d160778fd977825f10a07b49d738Adam Powell 20919a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 20929a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Set the user-visible name of this route. 20939a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param name Name to display to the user to describe this route 20949a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 20959a1de308cea2d160778fd977825f10a07b49d738Adam Powell public void setName(CharSequence name) { 2096eadd6d2329972129c96dee390a8b786b37313d17Hyundo Moon mNameResId = 0; 20979a1de308cea2d160778fd977825f10a07b49d738Adam Powell mName = name; 20989a1de308cea2d160778fd977825f10a07b49d738Adam Powell routeUpdated(); 20999a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 21005d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik 21010d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell /** 21020d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * Set the user-visible name of this route. 210356d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * <p> 210456d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * The route name identifies the destination represented by the route. 210556d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * It may be a user-supplied name, an alias, or device serial number. 210656d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * </p> 210756d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * 21080d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * @param resId Resource ID of the name to display to the user to describe this route 21090d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell */ 21100d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public void setName(int resId) { 21110d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell mNameResId = resId; 21120d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell mName = null; 21130d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell routeUpdated(); 21140d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell } 21159a1de308cea2d160778fd977825f10a07b49d738Adam Powell 21169a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 211756d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * Set the user-visible description of this route. 211856d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * <p> 211956d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * The route description describes the kind of destination represented by the route. 212056d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * It may be a user-supplied string, a model number or brand of device. 212156d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * </p> 212256d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * 212356d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown * @param description The description of the route, or null if none. 212456d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown */ 212556d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown public void setDescription(CharSequence description) { 212656d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown mDescription = description; 212756d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown routeUpdated(); 212856d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown } 212956d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown 213056d4b744b374af11f540567d2b43d66d8d7c301eJeff Brown /** 21319a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Set the current user-visible status for this route. 21329a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param status Status to display to the user to describe what the endpoint 21339a1de308cea2d160778fd977825f10a07b49d738Adam Powell * of this route is currently doing 21349a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 21359a1de308cea2d160778fd977825f10a07b49d738Adam Powell public void setStatus(CharSequence status) { 21369a1de308cea2d160778fd977825f10a07b49d738Adam Powell setStatusInt(status); 21379a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 2138ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell 2139ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell /** 2140ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * Set the RemoteControlClient responsible for reporting playback info for this 2141ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * user route. 2142ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * 2143ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * <p>If this route manages remote playback, the data exposed by this 2144ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * RemoteControlClient will be used to reflect and update information 2145ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * such as route volume info in related UIs.</p> 2146ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * 21471357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * <p>The RemoteControlClient must have been previously registered with 21481357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * {@link AudioManager#registerRemoteControlClient(RemoteControlClient)}.</p> 21491357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * 2150ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * @param rcc RemoteControlClient associated with this route 2151ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell */ 2152ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell public void setRemoteControlClient(RemoteControlClient rcc) { 2153ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell mRcc = rcc; 21541357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi updatePlaybackInfoOnRcc(); 2155ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell } 2156ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell 2157ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell /** 21584599696591f745b3a546197d2ba7e5cfc5562484Adam Powell * Retrieve the RemoteControlClient associated with this route, if one has been set. 21594599696591f745b3a546197d2ba7e5cfc5562484Adam Powell * 21604599696591f745b3a546197d2ba7e5cfc5562484Adam Powell * @return the RemoteControlClient associated with this route 21614599696591f745b3a546197d2ba7e5cfc5562484Adam Powell * @see #setRemoteControlClient(RemoteControlClient) 21624599696591f745b3a546197d2ba7e5cfc5562484Adam Powell */ 21634599696591f745b3a546197d2ba7e5cfc5562484Adam Powell public RemoteControlClient getRemoteControlClient() { 21644599696591f745b3a546197d2ba7e5cfc5562484Adam Powell return mRcc; 21654599696591f745b3a546197d2ba7e5cfc5562484Adam Powell } 21664599696591f745b3a546197d2ba7e5cfc5562484Adam Powell 21674599696591f745b3a546197d2ba7e5cfc5562484Adam Powell /** 2168ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * Set an icon that will be used to represent this route. 2169ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * The system may use this icon in picker UIs or similar. 2170ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * 2171ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * @param icon icon drawable to use to represent this route 2172ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell */ 2173ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell public void setIconDrawable(Drawable icon) { 2174ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell mIcon = icon; 2175ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell } 2176ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell 2177ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell /** 2178ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * Set an icon that will be used to represent this route. 2179ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * The system may use this icon in picker UIs or similar. 2180ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * 218171c69897ad0a55d590698bfa399bfe99c763b9dbAdam Powell * @param resId Resource ID of an icon drawable to use to represent this route 2182ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell */ 21837b9c912f536925ac6ec43935d6e97506851b33d6Tor Norbye public void setIconResource(@DrawableRes int resId) { 2184ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell setIconDrawable(sStatic.mResources.getDrawable(resId)); 2185ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell } 21861357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 21871357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 21881357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * Set a callback to be notified of volume update requests 21891357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @param vcb 21901357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 21911357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public void setVolumeCallback(VolumeCallback vcb) { 21921357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi mVcb = new VolumeCallbackInfo(vcb, this); 21931357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 21941357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 21951357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 21961357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * Defines whether playback associated with this route is "local" 21971357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * ({@link RouteInfo#PLAYBACK_TYPE_LOCAL}) or "remote" 21981357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * ({@link RouteInfo#PLAYBACK_TYPE_REMOTE}). 21991357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @param type 22001357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 22017c090d54e2c0eb5309d3f7dc131e137d9c986793Insun Kang public void setPlaybackType(@RouteInfo.PlaybackType int type) { 22021357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi if (mPlaybackType != type) { 22031357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi mPlaybackType = type; 2204430fc48865e5a371b08f180390946b96d73848feRoboErik configureSessionVolume(); 22051357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 22061357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 22071357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 22081357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 22091357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * Defines whether volume for the playback associated with this route is fixed 22101357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * ({@link RouteInfo#PLAYBACK_VOLUME_FIXED}) or can modified 22111357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * ({@link RouteInfo#PLAYBACK_VOLUME_VARIABLE}). 22121357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @param volumeHandling 22131357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 22147c090d54e2c0eb5309d3f7dc131e137d9c986793Insun Kang public void setVolumeHandling(@RouteInfo.PlaybackVolume int volumeHandling) { 22151357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi if (mVolumeHandling != volumeHandling) { 22161357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi mVolumeHandling = volumeHandling; 2217430fc48865e5a371b08f180390946b96d73848feRoboErik configureSessionVolume(); 22181357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 22191357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 22201357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 22211357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 22221357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * Defines at what volume the playback associated with this route is performed (for user 22231357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * feedback purposes). This information is only used when the playback is not local. 22241357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @param volume 22251357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 22261357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public void setVolume(int volume) { 22278e37a85bf3dc39519942698dc90a3951306b934bAdam Powell volume = Math.max(0, Math.min(volume, getVolumeMax())); 22281357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi if (mVolume != volume) { 22291357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi mVolume = volume; 2230430fc48865e5a371b08f180390946b96d73848feRoboErik if (mSvp != null) { 22310d0f67f5ee5f939a1b611bc4583212707afd9beeRoboErik mSvp.setCurrentVolume(mVolume); 22325d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik } 22338e37a85bf3dc39519942698dc90a3951306b934bAdam Powell dispatchRouteVolumeChanged(this); 2234f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell if (mGroup != null) { 2235f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell mGroup.memberVolumeChanged(this); 2236f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell } 22378e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 22388e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 22398e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 22408e37a85bf3dc39519942698dc90a3951306b934bAdam Powell @Override 22418e37a85bf3dc39519942698dc90a3951306b934bAdam Powell public void requestSetVolume(int volume) { 22428e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (mVolumeHandling == PLAYBACK_VOLUME_VARIABLE) { 22438e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (mVcb == null) { 22448e37a85bf3dc39519942698dc90a3951306b934bAdam Powell Log.e(TAG, "Cannot requestSetVolume on user route - no volume callback set"); 22458e37a85bf3dc39519942698dc90a3951306b934bAdam Powell return; 22468e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 22478e37a85bf3dc39519942698dc90a3951306b934bAdam Powell mVcb.vcb.onVolumeSetRequest(this, volume); 22488e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 22498e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 22508e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 22518e37a85bf3dc39519942698dc90a3951306b934bAdam Powell @Override 22528e37a85bf3dc39519942698dc90a3951306b934bAdam Powell public void requestUpdateVolume(int direction) { 22538e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (mVolumeHandling == PLAYBACK_VOLUME_VARIABLE) { 22548e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (mVcb == null) { 22558e37a85bf3dc39519942698dc90a3951306b934bAdam Powell Log.e(TAG, "Cannot requestChangeVolume on user route - no volumec callback set"); 22568e37a85bf3dc39519942698dc90a3951306b934bAdam Powell return; 22578e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 22588e37a85bf3dc39519942698dc90a3951306b934bAdam Powell mVcb.vcb.onVolumeUpdateRequest(this, direction); 22591357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 22601357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 22611357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 22621357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 22631357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * Defines the maximum volume at which the playback associated with this route is performed 22641357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * (for user feedback purposes). This information is only used when the playback is not 22651357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * local. 22661357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @param volumeMax 22671357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 22681357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public void setVolumeMax(int volumeMax) { 22691357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi if (mVolumeMax != volumeMax) { 22701357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi mVolumeMax = volumeMax; 2271430fc48865e5a371b08f180390946b96d73848feRoboErik configureSessionVolume(); 22721357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 22731357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 22741357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 22751357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 22761357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * Defines over what stream type the media is presented. 22771357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @param stream 22781357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 22791357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public void setPlaybackStream(int stream) { 22801357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi if (mPlaybackStream != stream) { 22811357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi mPlaybackStream = stream; 2282430fc48865e5a371b08f180390946b96d73848feRoboErik configureSessionVolume(); 22831357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 22841357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 22851357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 22861357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi private void updatePlaybackInfoOnRcc() { 2287430fc48865e5a371b08f180390946b96d73848feRoboErik configureSessionVolume(); 22885d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik } 22895d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik 22905d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik private void configureSessionVolume() { 22915d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik if (mRcc == null) { 22925d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik if (DEBUG) { 2293eadd6d2329972129c96dee390a8b786b37313d17Hyundo Moon Log.d(TAG, "No Rcc to configure volume for route " + getName()); 22945d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik } 22955d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik return; 22965d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik } 22975d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik MediaSession session = mRcc.getMediaSession(); 22985d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik if (session == null) { 22995d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik if (DEBUG) { 23005d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik Log.d(TAG, "Rcc has no session to configure volume"); 23015d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik } 23025d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik return; 23035d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik } 23045d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik if (mPlaybackType == RemoteControlClient.PLAYBACK_TYPE_REMOTE) { 23057c090d54e2c0eb5309d3f7dc131e137d9c986793Insun Kang @VolumeProvider.ControlType int volumeControl = 23067c090d54e2c0eb5309d3f7dc131e137d9c986793Insun Kang VolumeProvider.VOLUME_CONTROL_FIXED; 23075d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik switch (mVolumeHandling) { 23085d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik case RemoteControlClient.PLAYBACK_VOLUME_VARIABLE: 2309ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik volumeControl = VolumeProvider.VOLUME_CONTROL_ABSOLUTE; 23105d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik break; 23115d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik case RemoteControlClient.PLAYBACK_VOLUME_FIXED: 23125d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik default: 23135d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik break; 23141357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 23155d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik // Only register a new listener if necessary 23165d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik if (mSvp == null || mSvp.getVolumeControl() != volumeControl 23175d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik || mSvp.getMaxVolume() != mVolumeMax) { 23180d0f67f5ee5f939a1b611bc4583212707afd9beeRoboErik mSvp = new SessionVolumeProvider(volumeControl, mVolumeMax, mVolume); 23195d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik session.setPlaybackToRemote(mSvp); 23205d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik } 23215d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik } else { 23225d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik // We only know how to handle local and remote, fall back to local if not remote. 23239db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik AudioAttributes.Builder bob = new AudioAttributes.Builder(); 23249db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik bob.setLegacyStreamType(mPlaybackStream); 23259db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik session.setPlaybackToLocal(bob.build()); 23265d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik mSvp = null; 23271357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 23281357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 23291357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 2330ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik class SessionVolumeProvider extends VolumeProvider { 23315d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik 23327c090d54e2c0eb5309d3f7dc131e137d9c986793Insun Kang public SessionVolumeProvider(@VolumeProvider.ControlType int volumeControl, 23337c090d54e2c0eb5309d3f7dc131e137d9c986793Insun Kang int maxVolume, int currentVolume) { 23340d0f67f5ee5f939a1b611bc4583212707afd9beeRoboErik super(volumeControl, maxVolume, currentVolume); 23355d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik } 23365d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik 23375d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik @Override 23385d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik public void onSetVolumeTo(final int volume) { 23395d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik sStatic.mHandler.post(new Runnable() { 23405d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik @Override 23415d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik public void run() { 23425d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik if (mVcb != null) { 23435d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik mVcb.vcb.onVolumeSetRequest(mVcb.route, volume); 23445d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik } 23455d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik } 23465d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik }); 23475d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik } 23485d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik 23495d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik @Override 23501ff5b1648a051e9650614f0c0f1b3f449777db81RoboErik public void onAdjustVolume(final int direction) { 23515d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik sStatic.mHandler.post(new Runnable() { 23525d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik @Override 23535d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik public void run() { 23545d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik if (mVcb != null) { 23551ff5b1648a051e9650614f0c0f1b3f449777db81RoboErik mVcb.vcb.onVolumeUpdateRequest(mVcb.route, direction); 23565d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik } 23575d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik } 23585d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik }); 23595d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik } 23605d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik } 23619a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 23629a1de308cea2d160778fd977825f10a07b49d738Adam Powell 23639a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 23649a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Information about a route that consists of multiple other routes in a group. 23659a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 2366b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn public static class RouteGroup extends RouteInfo { 23679a1de308cea2d160778fd977825f10a07b49d738Adam Powell final ArrayList<RouteInfo> mRoutes = new ArrayList<RouteInfo>(); 23689a1de308cea2d160778fd977825f10a07b49d738Adam Powell private boolean mUpdateName; 23699a1de308cea2d160778fd977825f10a07b49d738Adam Powell 23709a1de308cea2d160778fd977825f10a07b49d738Adam Powell RouteGroup(RouteCategory category) { 23719a1de308cea2d160778fd977825f10a07b49d738Adam Powell super(category); 23729a1de308cea2d160778fd977825f10a07b49d738Adam Powell mGroup = this; 23738e37a85bf3dc39519942698dc90a3951306b934bAdam Powell mVolumeHandling = PLAYBACK_VOLUME_FIXED; 23749a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 23759a1de308cea2d160778fd977825f10a07b49d738Adam Powell 237669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown @Override 23770d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell CharSequence getName(Resources res) { 23789a1de308cea2d160778fd977825f10a07b49d738Adam Powell if (mUpdateName) updateName(); 23790d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell return super.getName(res); 23809a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 23819a1de308cea2d160778fd977825f10a07b49d738Adam Powell 23829a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 23839a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Add a route to this group. The route must not currently belong to another group. 23849a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 23859a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param route route to add to this group 23869a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 23879a1de308cea2d160778fd977825f10a07b49d738Adam Powell public void addRoute(RouteInfo route) { 23889a1de308cea2d160778fd977825f10a07b49d738Adam Powell if (route.getGroup() != null) { 23899a1de308cea2d160778fd977825f10a07b49d738Adam Powell throw new IllegalStateException("Route " + route + " is already part of a group."); 23909a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 23919a1de308cea2d160778fd977825f10a07b49d738Adam Powell if (route.getCategory() != mCategory) { 23929a1de308cea2d160778fd977825f10a07b49d738Adam Powell throw new IllegalArgumentException( 23939a1de308cea2d160778fd977825f10a07b49d738Adam Powell "Route cannot be added to a group with a different category. " + 23949a1de308cea2d160778fd977825f10a07b49d738Adam Powell "(Route category=" + route.getCategory() + 23959a1de308cea2d160778fd977825f10a07b49d738Adam Powell " group category=" + mCategory + ")"); 23969a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 2397d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell final int at = mRoutes.size(); 23989a1de308cea2d160778fd977825f10a07b49d738Adam Powell mRoutes.add(route); 2399d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell route.mGroup = this; 24009a1de308cea2d160778fd977825f10a07b49d738Adam Powell mUpdateName = true; 2401f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell updateVolume(); 24029a1de308cea2d160778fd977825f10a07b49d738Adam Powell routeUpdated(); 2403f3b653a21cdffe04c94c275e69ecb56e00766e82Adam Powell dispatchRouteGrouped(route, this, at); 24049a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 24059a1de308cea2d160778fd977825f10a07b49d738Adam Powell 24069a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 24079a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Add a route to this group before the specified index. 24089a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 24099a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param route route to add 24109a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param insertAt insert the new route before this index 24119a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 24129a1de308cea2d160778fd977825f10a07b49d738Adam Powell public void addRoute(RouteInfo route, int insertAt) { 24139a1de308cea2d160778fd977825f10a07b49d738Adam Powell if (route.getGroup() != null) { 24149a1de308cea2d160778fd977825f10a07b49d738Adam Powell throw new IllegalStateException("Route " + route + " is already part of a group."); 24159a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 24169a1de308cea2d160778fd977825f10a07b49d738Adam Powell if (route.getCategory() != mCategory) { 24179a1de308cea2d160778fd977825f10a07b49d738Adam Powell throw new IllegalArgumentException( 24189a1de308cea2d160778fd977825f10a07b49d738Adam Powell "Route cannot be added to a group with a different category. " + 24199a1de308cea2d160778fd977825f10a07b49d738Adam Powell "(Route category=" + route.getCategory() + 24209a1de308cea2d160778fd977825f10a07b49d738Adam Powell " group category=" + mCategory + ")"); 24219a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 24229a1de308cea2d160778fd977825f10a07b49d738Adam Powell mRoutes.add(insertAt, route); 2423d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell route.mGroup = this; 24249a1de308cea2d160778fd977825f10a07b49d738Adam Powell mUpdateName = true; 2425f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell updateVolume(); 24269a1de308cea2d160778fd977825f10a07b49d738Adam Powell routeUpdated(); 2427f3b653a21cdffe04c94c275e69ecb56e00766e82Adam Powell dispatchRouteGrouped(route, this, insertAt); 24289a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 24299a1de308cea2d160778fd977825f10a07b49d738Adam Powell 24309a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 24319a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Remove a route from this group. 24329a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 24339a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param route route to remove 24349a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 24359a1de308cea2d160778fd977825f10a07b49d738Adam Powell public void removeRoute(RouteInfo route) { 24369a1de308cea2d160778fd977825f10a07b49d738Adam Powell if (route.getGroup() != this) { 24379a1de308cea2d160778fd977825f10a07b49d738Adam Powell throw new IllegalArgumentException("Route " + route + 24389a1de308cea2d160778fd977825f10a07b49d738Adam Powell " is not a member of this group."); 24399a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 24409a1de308cea2d160778fd977825f10a07b49d738Adam Powell mRoutes.remove(route); 2441d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell route.mGroup = null; 24429a1de308cea2d160778fd977825f10a07b49d738Adam Powell mUpdateName = true; 2443f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell updateVolume(); 2444d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell dispatchRouteUngrouped(route, this); 24459a1de308cea2d160778fd977825f10a07b49d738Adam Powell routeUpdated(); 24469a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 24479a1de308cea2d160778fd977825f10a07b49d738Adam Powell 24489a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 24499a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Remove the route at the specified index from this group. 24509a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 24519a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param index index of the route to remove 24529a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 24539a1de308cea2d160778fd977825f10a07b49d738Adam Powell public void removeRoute(int index) { 2454d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell RouteInfo route = mRoutes.remove(index); 2455d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell route.mGroup = null; 24569a1de308cea2d160778fd977825f10a07b49d738Adam Powell mUpdateName = true; 2457f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell updateVolume(); 2458d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell dispatchRouteUngrouped(route, this); 24599a1de308cea2d160778fd977825f10a07b49d738Adam Powell routeUpdated(); 24609a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 24619a1de308cea2d160778fd977825f10a07b49d738Adam Powell 2462d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell /** 2463d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @return The number of routes in this group 2464d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell */ 2465d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell public int getRouteCount() { 2466d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell return mRoutes.size(); 2467d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell } 2468d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell 2469d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell /** 2470d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * Return the route in this group at the specified index 2471d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * 2472d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param index Index to fetch 2473d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @return The route at index 2474d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell */ 2475d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell public RouteInfo getRouteAt(int index) { 2476d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell return mRoutes.get(index); 2477d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell } 2478d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell 2479ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell /** 2480ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * Set an icon that will be used to represent this group. 2481ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * The system may use this icon in picker UIs or similar. 2482ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * 2483ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * @param icon icon drawable to use to represent this group 2484ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell */ 2485ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell public void setIconDrawable(Drawable icon) { 2486ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell mIcon = icon; 2487ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell } 2488ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell 2489ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell /** 2490ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * Set an icon that will be used to represent this group. 2491ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * The system may use this icon in picker UIs or similar. 2492ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * 249371c69897ad0a55d590698bfa399bfe99c763b9dbAdam Powell * @param resId Resource ID of an icon drawable to use to represent this group 2494ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell */ 24957b9c912f536925ac6ec43935d6e97506851b33d6Tor Norbye public void setIconResource(@DrawableRes int resId) { 2496ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell setIconDrawable(sStatic.mResources.getDrawable(resId)); 2497ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell } 2498ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell 24998e37a85bf3dc39519942698dc90a3951306b934bAdam Powell @Override 25008e37a85bf3dc39519942698dc90a3951306b934bAdam Powell public void requestSetVolume(int volume) { 25018e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final int maxVol = getVolumeMax(); 25028e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (maxVol == 0) { 25038e37a85bf3dc39519942698dc90a3951306b934bAdam Powell return; 25048e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 25058e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 25068e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final float scaledVolume = (float) volume / maxVol; 25078e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final int routeCount = getRouteCount(); 25088e37a85bf3dc39519942698dc90a3951306b934bAdam Powell for (int i = 0; i < routeCount; i++) { 25098e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final RouteInfo route = getRouteAt(i); 25108e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final int routeVol = (int) (scaledVolume * route.getVolumeMax()); 25118e37a85bf3dc39519942698dc90a3951306b934bAdam Powell route.requestSetVolume(routeVol); 25128e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 25138e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (volume != mVolume) { 25148e37a85bf3dc39519942698dc90a3951306b934bAdam Powell mVolume = volume; 25158e37a85bf3dc39519942698dc90a3951306b934bAdam Powell dispatchRouteVolumeChanged(this); 25168e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 25178e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 25188e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 25198e37a85bf3dc39519942698dc90a3951306b934bAdam Powell @Override 25208e37a85bf3dc39519942698dc90a3951306b934bAdam Powell public void requestUpdateVolume(int direction) { 25218e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final int maxVol = getVolumeMax(); 25228e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (maxVol == 0) { 25238e37a85bf3dc39519942698dc90a3951306b934bAdam Powell return; 25248e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 25258e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 25268e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final int routeCount = getRouteCount(); 2527f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell int volume = 0; 25288e37a85bf3dc39519942698dc90a3951306b934bAdam Powell for (int i = 0; i < routeCount; i++) { 25298e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final RouteInfo route = getRouteAt(i); 25308e37a85bf3dc39519942698dc90a3951306b934bAdam Powell route.requestUpdateVolume(direction); 2531f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell final int routeVol = route.getVolume(); 2532f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell if (routeVol > volume) { 2533f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell volume = routeVol; 2534f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell } 25358e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 25368e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (volume != mVolume) { 25378e37a85bf3dc39519942698dc90a3951306b934bAdam Powell mVolume = volume; 25388e37a85bf3dc39519942698dc90a3951306b934bAdam Powell dispatchRouteVolumeChanged(this); 25398e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 25408e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 25418e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 25429a1de308cea2d160778fd977825f10a07b49d738Adam Powell void memberNameChanged(RouteInfo info, CharSequence name) { 25439a1de308cea2d160778fd977825f10a07b49d738Adam Powell mUpdateName = true; 25449a1de308cea2d160778fd977825f10a07b49d738Adam Powell routeUpdated(); 25459a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 25469a1de308cea2d160778fd977825f10a07b49d738Adam Powell 25479a1de308cea2d160778fd977825f10a07b49d738Adam Powell void memberStatusChanged(RouteInfo info, CharSequence status) { 25489a1de308cea2d160778fd977825f10a07b49d738Adam Powell setStatusInt(status); 25499a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 25509a1de308cea2d160778fd977825f10a07b49d738Adam Powell 2551f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell void memberVolumeChanged(RouteInfo info) { 2552f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell updateVolume(); 2553f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell } 2554f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell 2555f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell void updateVolume() { 2556f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell // A group always represents the highest component volume value. 2557f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell final int routeCount = getRouteCount(); 2558f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell int volume = 0; 2559f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell for (int i = 0; i < routeCount; i++) { 2560f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell final int routeVol = getRouteAt(i).getVolume(); 2561f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell if (routeVol > volume) { 2562f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell volume = routeVol; 2563f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell } 2564f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell } 2565f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell if (volume != mVolume) { 2566f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell mVolume = volume; 2567f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell dispatchRouteVolumeChanged(this); 2568f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell } 2569f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell } 2570f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell 2571d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell @Override 2572d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell void routeUpdated() { 2573d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell int types = 0; 2574d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell final int count = mRoutes.size(); 2575b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell if (count == 0) { 2576b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell // Don't keep empty groups in the router. 257769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown MediaRouter.removeRouteStatic(this); 2578b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell return; 2579b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell } 2580b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell 25818e37a85bf3dc39519942698dc90a3951306b934bAdam Powell int maxVolume = 0; 25828e37a85bf3dc39519942698dc90a3951306b934bAdam Powell boolean isLocal = true; 25838e37a85bf3dc39519942698dc90a3951306b934bAdam Powell boolean isFixedVolume = true; 2584d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell for (int i = 0; i < count; i++) { 25858e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final RouteInfo route = mRoutes.get(i); 25868e37a85bf3dc39519942698dc90a3951306b934bAdam Powell types |= route.mSupportedTypes; 25878e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final int routeMaxVolume = route.getVolumeMax(); 25888e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (routeMaxVolume > maxVolume) { 25898e37a85bf3dc39519942698dc90a3951306b934bAdam Powell maxVolume = routeMaxVolume; 25908e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 25918e37a85bf3dc39519942698dc90a3951306b934bAdam Powell isLocal &= route.getPlaybackType() == PLAYBACK_TYPE_LOCAL; 25928e37a85bf3dc39519942698dc90a3951306b934bAdam Powell isFixedVolume &= route.getVolumeHandling() == PLAYBACK_VOLUME_FIXED; 2593d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell } 25948e37a85bf3dc39519942698dc90a3951306b934bAdam Powell mPlaybackType = isLocal ? PLAYBACK_TYPE_LOCAL : PLAYBACK_TYPE_REMOTE; 25958e37a85bf3dc39519942698dc90a3951306b934bAdam Powell mVolumeHandling = isFixedVolume ? PLAYBACK_VOLUME_FIXED : PLAYBACK_VOLUME_VARIABLE; 2596d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell mSupportedTypes = types; 25978e37a85bf3dc39519942698dc90a3951306b934bAdam Powell mVolumeMax = maxVolume; 2598d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell mIcon = count == 1 ? mRoutes.get(0).getIconDrawable() : null; 2599d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell super.routeUpdated(); 2600d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell } 2601d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell 26029a1de308cea2d160778fd977825f10a07b49d738Adam Powell void updateName() { 26039a1de308cea2d160778fd977825f10a07b49d738Adam Powell final StringBuilder sb = new StringBuilder(); 26049a1de308cea2d160778fd977825f10a07b49d738Adam Powell final int count = mRoutes.size(); 26059a1de308cea2d160778fd977825f10a07b49d738Adam Powell for (int i = 0; i < count; i++) { 26069a1de308cea2d160778fd977825f10a07b49d738Adam Powell final RouteInfo info = mRoutes.get(i); 2607b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell // TODO: There's probably a much more correct way to localize this. 2608eadd6d2329972129c96dee390a8b786b37313d17Hyundo Moon if (i > 0) { 2609eadd6d2329972129c96dee390a8b786b37313d17Hyundo Moon sb.append(", "); 2610eadd6d2329972129c96dee390a8b786b37313d17Hyundo Moon } 2611eadd6d2329972129c96dee390a8b786b37313d17Hyundo Moon sb.append(info.getName()); 26129a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 26139a1de308cea2d160778fd977825f10a07b49d738Adam Powell mName = sb.toString(); 26149a1de308cea2d160778fd977825f10a07b49d738Adam Powell mUpdateName = false; 26159a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 2616d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell 2617d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell @Override 2618d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell public String toString() { 2619d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell StringBuilder sb = new StringBuilder(super.toString()); 2620d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell sb.append('['); 2621d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell final int count = mRoutes.size(); 2622d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell for (int i = 0; i < count; i++) { 2623d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell if (i > 0) sb.append(", "); 2624d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell sb.append(mRoutes.get(i)); 2625d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell } 2626d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell sb.append(']'); 2627d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell return sb.toString(); 2628d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell } 26299a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 26309a1de308cea2d160778fd977825f10a07b49d738Adam Powell 26319a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 26329a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Definition of a category of routes. All routes belong to a category. 26339a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 2634b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn public static class RouteCategory { 26359a1de308cea2d160778fd977825f10a07b49d738Adam Powell CharSequence mName; 26360d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell int mNameResId; 26379a1de308cea2d160778fd977825f10a07b49d738Adam Powell int mTypes; 26389a1de308cea2d160778fd977825f10a07b49d738Adam Powell final boolean mGroupable; 2639705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell boolean mIsSystem; 26409a1de308cea2d160778fd977825f10a07b49d738Adam Powell 26419a1de308cea2d160778fd977825f10a07b49d738Adam Powell RouteCategory(CharSequence name, int types, boolean groupable) { 26429a1de308cea2d160778fd977825f10a07b49d738Adam Powell mName = name; 26439a1de308cea2d160778fd977825f10a07b49d738Adam Powell mTypes = types; 26449a1de308cea2d160778fd977825f10a07b49d738Adam Powell mGroupable = groupable; 26459a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 26469a1de308cea2d160778fd977825f10a07b49d738Adam Powell 26470d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell RouteCategory(int nameResId, int types, boolean groupable) { 26480d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell mNameResId = nameResId; 26490d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell mTypes = types; 26500d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell mGroupable = groupable; 26510d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell } 26520d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell 26539a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 26549a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @return the name of this route category 26559a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 26569a1de308cea2d160778fd977825f10a07b49d738Adam Powell public CharSequence getName() { 26570d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell return getName(sStatic.mResources); 26580d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell } 26595d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik 26600d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell /** 26610d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * Return the properly localized/configuration dependent name of this RouteCategory. 26625d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik * 26630d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * @param context Context to resolve name resources 26640d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * @return the name of this route category 26650d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell */ 26660d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public CharSequence getName(Context context) { 26670d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell return getName(context.getResources()); 26680d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell } 26695d3114b64a88ac1f72becd8d46f148c666f64aa3RoboErik 26700d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell CharSequence getName(Resources res) { 26710d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell if (mNameResId != 0) { 26720d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell return res.getText(mNameResId); 26730d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell } 26749a1de308cea2d160778fd977825f10a07b49d738Adam Powell return mName; 26759a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 26769a1de308cea2d160778fd977825f10a07b49d738Adam Powell 26779a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 2678d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * Return the current list of routes in this category that have been added 2679d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * to the MediaRouter. 26809a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 2681d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * <p>This list will not include routes that are nested within RouteGroups. 2682d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * A RouteGroup is treated as a single route within its category.</p> 2683d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * 2684d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param out a List to fill with the routes in this category. If this parameter is 2685d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * non-null, it will be cleared, filled with the current routes with this 2686d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * category, and returned. If this parameter is null, a new List will be 2687d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * allocated to report the category's current routes. 2688d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @return A list with the routes in this category that have been added to the MediaRouter. 26899a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 2690d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell public List<RouteInfo> getRoutes(List<RouteInfo> out) { 2691d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell if (out == null) { 2692d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell out = new ArrayList<RouteInfo>(); 2693d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell } else { 2694d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell out.clear(); 2695d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell } 2696d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell 2697b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn final int count = getRouteCountStatic(); 2698d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell for (int i = 0; i < count; i++) { 2699b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn final RouteInfo route = getRouteAtStatic(i); 2700d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell if (route.mCategory == this) { 2701d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell out.add(route); 2702d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell } 2703d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell } 2704d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell return out; 27059a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 27069a1de308cea2d160778fd977825f10a07b49d738Adam Powell 27079a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 27089a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @return Flag set describing the route types supported by this category 27099a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 27109a1de308cea2d160778fd977825f10a07b49d738Adam Powell public int getSupportedTypes() { 27119a1de308cea2d160778fd977825f10a07b49d738Adam Powell return mTypes; 27129a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 27139a1de308cea2d160778fd977825f10a07b49d738Adam Powell 27149a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 27159a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Return whether or not this category supports grouping. 27169a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 27179a1de308cea2d160778fd977825f10a07b49d738Adam Powell * <p>If this method returns true, all routes obtained from this category 2718d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * via calls to {@link #getRouteAt(int)} will be {@link MediaRouter.RouteGroup}s.</p> 27199a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 27209a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @return true if this category supports 27219a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 27229a1de308cea2d160778fd977825f10a07b49d738Adam Powell public boolean isGroupable() { 27239a1de308cea2d160778fd977825f10a07b49d738Adam Powell return mGroupable; 27249a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 27259a1de308cea2d160778fd977825f10a07b49d738Adam Powell 2726705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell /** 2727705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell * @return true if this is the category reserved for system routes. 2728705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell * @hide 2729705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell */ 2730705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell public boolean isSystem() { 2731705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell return mIsSystem; 2732705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 2733705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell 273469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown @Override 27359a1de308cea2d160778fd977825f10a07b49d738Adam Powell public String toString() { 2736eadd6d2329972129c96dee390a8b786b37313d17Hyundo Moon return "RouteCategory{ name=" + getName() + " types=" + typesToString(mTypes) + 2737d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell " groupable=" + mGroupable + " }"; 27389a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 27399a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 27409a1de308cea2d160778fd977825f10a07b49d738Adam Powell 27419a1de308cea2d160778fd977825f10a07b49d738Adam Powell static class CallbackInfo { 27429a1de308cea2d160778fd977825f10a07b49d738Adam Powell public int type; 274366f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown public int flags; 2744b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn public final Callback cb; 2745b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn public final MediaRouter router; 27469a1de308cea2d160778fd977825f10a07b49d738Adam Powell 274766f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown public CallbackInfo(Callback cb, int type, int flags, MediaRouter router) { 27489a1de308cea2d160778fd977825f10a07b49d738Adam Powell this.cb = cb; 27499a1de308cea2d160778fd977825f10a07b49d738Adam Powell this.type = type; 275066f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown this.flags = flags; 2751b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn this.router = router; 27529a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 275366f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown 275466f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown public boolean filterRouteEvent(RouteInfo route) { 2755af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown return filterRouteEvent(route.mSupportedTypes); 2756af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown } 2757af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown 2758af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown public boolean filterRouteEvent(int supportedTypes) { 275966f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown return (flags & CALLBACK_FLAG_UNFILTERED_EVENTS) != 0 2760af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown || (type & supportedTypes) != 0; 276166f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown } 27629a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 27639a1de308cea2d160778fd977825f10a07b49d738Adam Powell 27649a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 27659a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Interface for receiving events about media routing changes. 27669a1de308cea2d160778fd977825f10a07b49d738Adam Powell * All methods of this interface will be called from the application's main thread. 276766f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * <p> 276866f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * A Callback will only receive events relevant to routes that the callback 276966f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * was registered for unless the {@link MediaRouter#CALLBACK_FLAG_UNFILTERED_EVENTS} 277066f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * flag was specified in {@link MediaRouter#addCallback(int, Callback, int)}. 277166f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * </p> 27729a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 277366f3b39ec452a8a03e3254e77e19ccb764ee931fJeff Brown * @see MediaRouter#addCallback(int, Callback, int) 27749a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @see MediaRouter#removeCallback(Callback) 27759a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 27760d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public static abstract class Callback { 27779a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 27789a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Called when the supplied route becomes selected as the active route 27799a1de308cea2d160778fd977825f10a07b49d738Adam Powell * for the given route type. 27809a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 2781d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param router the MediaRouter reporting the event 27829a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param type Type flag set indicating the routes that have been selected 27839a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param info Route that has been selected for the given route types 27849a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 27850d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public abstract void onRouteSelected(MediaRouter router, int type, RouteInfo info); 27869a1de308cea2d160778fd977825f10a07b49d738Adam Powell 27879a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 27889a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Called when the supplied route becomes unselected as the active route 27899a1de308cea2d160778fd977825f10a07b49d738Adam Powell * for the given route type. 27909a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 2791d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param router the MediaRouter reporting the event 27929a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param type Type flag set indicating the routes that have been unselected 27939a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param info Route that has been unselected for the given route types 27949a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 27950d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public abstract void onRouteUnselected(MediaRouter router, int type, RouteInfo info); 27969a1de308cea2d160778fd977825f10a07b49d738Adam Powell 27979a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 27989a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Called when a route for the specified type was added. 27999a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 2800d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param router the MediaRouter reporting the event 28019a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param info Route that has become available for use 28029a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 28030d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public abstract void onRouteAdded(MediaRouter router, RouteInfo info); 28049a1de308cea2d160778fd977825f10a07b49d738Adam Powell 28059a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 28069a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Called when a route for the specified type was removed. 28079a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 2808d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param router the MediaRouter reporting the event 28099a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param info Route that has been removed from availability 28109a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 28110d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public abstract void onRouteRemoved(MediaRouter router, RouteInfo info); 28129a1de308cea2d160778fd977825f10a07b49d738Adam Powell 28139a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 28149a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Called when an aspect of the indicated route has changed. 28159a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 28169a1de308cea2d160778fd977825f10a07b49d738Adam Powell * <p>This will not indicate that the types supported by this route have 28179a1de308cea2d160778fd977825f10a07b49d738Adam Powell * changed, only that cosmetic info such as name or status have been updated.</p> 28189a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 2819d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param router the MediaRouter reporting the event 28209a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param info The route that was changed 28219a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 28220d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public abstract void onRouteChanged(MediaRouter router, RouteInfo info); 2823d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell 2824d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell /** 2825d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * Called when a route is added to a group. 2826d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * 2827d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param router the MediaRouter reporting the event 2828d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param info The route that was added 2829d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param group The group the route was added to 2830d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param index The route index within group that info was added at 2831d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell */ 28320d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public abstract void onRouteGrouped(MediaRouter router, RouteInfo info, RouteGroup group, 28330d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell int index); 2834d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell 2835d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell /** 2836d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * Called when a route is removed from a group. 2837d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * 2838d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param router the MediaRouter reporting the event 2839d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param info The route that was removed 2840d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param group The group the route was removed from 2841d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell */ 28420d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public abstract void onRouteUngrouped(MediaRouter router, RouteInfo info, RouteGroup group); 28438e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 28448e37a85bf3dc39519942698dc90a3951306b934bAdam Powell /** 28458e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * Called when a route's volume changes. 28468e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * 28478e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * @param router the MediaRouter reporting the event 28488e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * @param info The route with altered volume 28498e37a85bf3dc39519942698dc90a3951306b934bAdam Powell */ 28508e37a85bf3dc39519942698dc90a3951306b934bAdam Powell public abstract void onRouteVolumeChanged(MediaRouter router, RouteInfo info); 285192130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown 285292130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown /** 285392130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * Called when a route's presentation display changes. 285492130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * <p> 285592130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * This method is called whenever the route's presentation display becomes 285692130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * available, is removes or has changes to some of its properties (such as its size). 285792130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * </p> 285892130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * 285992130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * @param router the MediaRouter reporting the event 286092130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * @param info The route whose presentation display changed 286192130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * 286292130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown * @see RouteInfo#getPresentationDisplay() 286392130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown */ 286492130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown public void onRoutePresentationDisplayChanged(MediaRouter router, RouteInfo info) { 286592130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown } 28669a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 28679a1de308cea2d160778fd977825f10a07b49d738Adam Powell 28689a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 28690d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * Stub implementation of {@link MediaRouter.Callback}. 28700d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * Each abstract method is defined as a no-op. Override just the ones 28719a1de308cea2d160778fd977825f10a07b49d738Adam Powell * you need. 28729a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 28730d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public static class SimpleCallback extends Callback { 28749a1de308cea2d160778fd977825f10a07b49d738Adam Powell 28759a1de308cea2d160778fd977825f10a07b49d738Adam Powell @Override 2876d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell public void onRouteSelected(MediaRouter router, int type, RouteInfo info) { 28779a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 28789a1de308cea2d160778fd977825f10a07b49d738Adam Powell 28799a1de308cea2d160778fd977825f10a07b49d738Adam Powell @Override 2880d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell public void onRouteUnselected(MediaRouter router, int type, RouteInfo info) { 28819a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 28829a1de308cea2d160778fd977825f10a07b49d738Adam Powell 28839a1de308cea2d160778fd977825f10a07b49d738Adam Powell @Override 2884d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell public void onRouteAdded(MediaRouter router, RouteInfo info) { 28859a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 28869a1de308cea2d160778fd977825f10a07b49d738Adam Powell 28879a1de308cea2d160778fd977825f10a07b49d738Adam Powell @Override 2888d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell public void onRouteRemoved(MediaRouter router, RouteInfo info) { 28899a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 28909a1de308cea2d160778fd977825f10a07b49d738Adam Powell 28919a1de308cea2d160778fd977825f10a07b49d738Adam Powell @Override 2892d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell public void onRouteChanged(MediaRouter router, RouteInfo info) { 28939a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 28949a1de308cea2d160778fd977825f10a07b49d738Adam Powell 28959a1de308cea2d160778fd977825f10a07b49d738Adam Powell @Override 2896d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell public void onRouteGrouped(MediaRouter router, RouteInfo info, RouteGroup group, 2897d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell int index) { 28989a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 28999a1de308cea2d160778fd977825f10a07b49d738Adam Powell 29009a1de308cea2d160778fd977825f10a07b49d738Adam Powell @Override 2901d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell public void onRouteUngrouped(MediaRouter router, RouteInfo info, RouteGroup group) { 29029a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 2903d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell 29048e37a85bf3dc39519942698dc90a3951306b934bAdam Powell @Override 29058e37a85bf3dc39519942698dc90a3951306b934bAdam Powell public void onRouteVolumeChanged(MediaRouter router, RouteInfo info) { 29068e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 29079a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 29081357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 29091357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi static class VolumeCallbackInfo { 29101357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public final VolumeCallback vcb; 29111357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public final RouteInfo route; 29121357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 29131357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public VolumeCallbackInfo(VolumeCallback vcb, RouteInfo route) { 29141357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi this.vcb = vcb; 29151357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi this.route = route; 29161357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 29171357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 29181357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 29191357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 29201357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * Interface for receiving events about volume changes. 29211357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * All methods of this interface will be called from the application's main thread. 29221357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * 29231357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * <p>A VolumeCallback will only receive events relevant to routes that the callback 29241357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * was registered for.</p> 29251357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * 29261357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @see UserRouteInfo#setVolumeCallback(VolumeCallback) 29271357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 29281357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public static abstract class VolumeCallback { 29291357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 29301357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * Called when the volume for the route should be increased or decreased. 29311357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @param info the route affected by this event 29321357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @param direction an integer indicating whether the volume is to be increased 29331357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * (positive value) or decreased (negative value). 29341357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * For bundled changes, the absolute value indicates the number of changes 29351357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * in the same direction, e.g. +3 corresponds to three "volume up" changes. 29361357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 29371357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public abstract void onVolumeUpdateRequest(RouteInfo info, int direction); 29381357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 29391357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * Called when the volume for the route should be set to the given value 29401357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @param info the route affected by this event 29411357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @param volume an integer indicating the new volume value that should be used, always 29421357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * between 0 and the value set by {@link UserRouteInfo#setVolumeMax(int)}. 29431357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 29441357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public abstract void onVolumeSetRequest(RouteInfo info, int volume); 29451357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 29461357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 29478e37a85bf3dc39519942698dc90a3951306b934bAdam Powell static class VolumeChangeReceiver extends BroadcastReceiver { 29488e37a85bf3dc39519942698dc90a3951306b934bAdam Powell @Override 29498e37a85bf3dc39519942698dc90a3951306b934bAdam Powell public void onReceive(Context context, Intent intent) { 29508e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (intent.getAction().equals(AudioManager.VOLUME_CHANGED_ACTION)) { 29518e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final int streamType = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, 29528e37a85bf3dc39519942698dc90a3951306b934bAdam Powell -1); 29538e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (streamType != AudioManager.STREAM_MUSIC) { 29548e37a85bf3dc39519942698dc90a3951306b934bAdam Powell return; 29558e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 29568e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 29578e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final int newVolume = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, 0); 29588e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final int oldVolume = intent.getIntExtra( 29598e37a85bf3dc39519942698dc90a3951306b934bAdam Powell AudioManager.EXTRA_PREV_VOLUME_STREAM_VALUE, 0); 29608e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (newVolume != oldVolume) { 29618e37a85bf3dc39519942698dc90a3951306b934bAdam Powell systemVolumeChanged(newVolume); 29628e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 29638e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 29648e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 2965705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 29668e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 2967705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell static class WifiDisplayStatusChangedReceiver extends BroadcastReceiver { 2968705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell @Override 2969705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell public void onReceive(Context context, Intent intent) { 2970705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell if (intent.getAction().equals(DisplayManager.ACTION_WIFI_DISPLAY_STATUS_CHANGED)) { 2971705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell updateWifiDisplayStatus((WifiDisplayStatus) intent.getParcelableExtra( 2972705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell DisplayManager.EXTRA_WIFI_DISPLAY_STATUS)); 2973705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 2974705ab808cf023e0cc38c2ba7cdb9571942cdc04fAdam Powell } 29758e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 29769a1de308cea2d160778fd977825f10a07b49d738Adam Powell} 2977