MediaRouter.java revision dbbfa702a09f6d2d36dee1b552442d04a4673f89
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 198e37a85bf3dc39519942698dc90a3951306b934bAdam Powellimport android.content.BroadcastReceiver; 209a1de308cea2d160778fd977825f10a07b49d738Adam Powellimport android.content.Context; 218e37a85bf3dc39519942698dc90a3951306b934bAdam Powellimport android.content.Intent; 228e37a85bf3dc39519942698dc90a3951306b934bAdam Powellimport android.content.IntentFilter; 23b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackbornimport android.content.res.Resources; 24ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powellimport android.graphics.drawable.Drawable; 259a1de308cea2d160778fd977825f10a07b49d738Adam Powellimport android.os.Handler; 26632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackbornimport android.os.IBinder; 27632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackbornimport android.os.RemoteException; 28632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackbornimport android.os.ServiceManager; 29632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackbornimport android.text.TextUtils; 309a1de308cea2d160778fd977825f10a07b49d738Adam Powellimport android.util.Log; 319a1de308cea2d160778fd977825f10a07b49d738Adam Powell 329a1de308cea2d160778fd977825f10a07b49d738Adam Powellimport java.util.ArrayList; 339a1de308cea2d160778fd977825f10a07b49d738Adam Powellimport java.util.HashMap; 34d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powellimport java.util.List; 3539d5c6172503620ac3761148adac5fd7fa20d02dAdam Powellimport java.util.concurrent.CopyOnWriteArrayList; 369a1de308cea2d160778fd977825f10a07b49d738Adam Powell 379a1de308cea2d160778fd977825f10a07b49d738Adam Powell/** 389a1de308cea2d160778fd977825f10a07b49d738Adam Powell * MediaRouter allows applications to control the routing of media channels 399a1de308cea2d160778fd977825f10a07b49d738Adam Powell * and streams from the current device to external speakers and destination devices. 409a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 41b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn * <p>A MediaRouter is retrieved through {@link Context#getSystemService(String) 42b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn * Context.getSystemService()} of a {@link Context#MEDIA_ROUTER_SERVICE 43b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn * Context.MEDIA_ROUTER_SERVICE}. 44b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn * 45b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn * <p>The media router API is not thread-safe; all interactions with it must be 46b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn * done from the main thread of the process.</p> 479a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 489a1de308cea2d160778fd977825f10a07b49d738Adam Powellpublic class MediaRouter { 499a1de308cea2d160778fd977825f10a07b49d738Adam Powell private static final String TAG = "MediaRouter"; 509a1de308cea2d160778fd977825f10a07b49d738Adam Powell 51b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn static class Static { 52b35c445f34e1a18e17aef3e3dfbc1c39b4d1815cAdam Powell final Resources mResources; 53632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn final IAudioService mAudioService; 54b35c445f34e1a18e17aef3e3dfbc1c39b4d1815cAdam Powell final Handler mHandler; 5539d5c6172503620ac3761148adac5fd7fa20d02dAdam Powell final CopyOnWriteArrayList<CallbackInfo> mCallbacks = 5639d5c6172503620ac3761148adac5fd7fa20d02dAdam Powell new CopyOnWriteArrayList<CallbackInfo>(); 57b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn 58b35c445f34e1a18e17aef3e3dfbc1c39b4d1815cAdam Powell final ArrayList<RouteInfo> mRoutes = new ArrayList<RouteInfo>(); 59b35c445f34e1a18e17aef3e3dfbc1c39b4d1815cAdam Powell final ArrayList<RouteCategory> mCategories = new ArrayList<RouteCategory>(); 60b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn 61b35c445f34e1a18e17aef3e3dfbc1c39b4d1815cAdam Powell final RouteCategory mSystemCategory; 62632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn 63632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn final AudioRoutesInfo mCurRoutesInfo = new AudioRoutesInfo(); 64b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn 65b35c445f34e1a18e17aef3e3dfbc1c39b4d1815cAdam Powell RouteInfo mDefaultAudio; 66b35c445f34e1a18e17aef3e3dfbc1c39b4d1815cAdam Powell RouteInfo mBluetoothA2dpRoute; 67b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn 68b35c445f34e1a18e17aef3e3dfbc1c39b4d1815cAdam Powell RouteInfo mSelectedRoute; 699a1de308cea2d160778fd977825f10a07b49d738Adam Powell 70632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn final IAudioRoutesObserver.Stub mRoutesObserver = new IAudioRoutesObserver.Stub() { 71632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn public void dispatchAudioRoutesChanged(final AudioRoutesInfo newRoutes) { 72632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn mHandler.post(new Runnable() { 73632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn @Override public void run() { 74632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn updateRoutes(newRoutes); 75632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } 76632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn }); 77632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } 78632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn }; 79632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn 80b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn Static(Context appContext) { 81b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn mResources = Resources.getSystem(); 82b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn mHandler = new Handler(appContext.getMainLooper()); 839a1de308cea2d160778fd977825f10a07b49d738Adam Powell 84632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn IBinder b = ServiceManager.getService(Context.AUDIO_SERVICE); 85632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn mAudioService = IAudioService.Stub.asInterface(b); 869a1de308cea2d160778fd977825f10a07b49d738Adam Powell 87dd0a19266d5c837069da1ea188744d54c8d723a8Adam Powell mSystemCategory = new RouteCategory( 88dd0a19266d5c837069da1ea188744d54c8d723a8Adam Powell com.android.internal.R.string.default_audio_route_category_name, 89b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn ROUTE_TYPE_LIVE_AUDIO, false); 90b35c445f34e1a18e17aef3e3dfbc1c39b4d1815cAdam Powell } 91b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn 92b35c445f34e1a18e17aef3e3dfbc1c39b4d1815cAdam Powell // Called after sStatic is initialized 938e37a85bf3dc39519942698dc90a3951306b934bAdam Powell void startMonitoringRoutes(Context appContext) { 94b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn mDefaultAudio = new RouteInfo(mSystemCategory); 950d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell mDefaultAudio.mNameResId = com.android.internal.R.string.default_audio_route_name; 96b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn mDefaultAudio.mSupportedTypes = ROUTE_TYPE_LIVE_AUDIO; 97b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn addRoute(mDefaultAudio); 98632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn 998e37a85bf3dc39519942698dc90a3951306b934bAdam Powell appContext.registerReceiver(new VolumeChangeReceiver(), 1008e37a85bf3dc39519942698dc90a3951306b934bAdam Powell new IntentFilter(AudioManager.VOLUME_CHANGED_ACTION)); 1018e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 102632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn AudioRoutesInfo newRoutes = null; 103632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn try { 104632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn newRoutes = mAudioService.startWatchingRoutes(mRoutesObserver); 105632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } catch (RemoteException e) { 106632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } 107632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn if (newRoutes != null) { 108632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn updateRoutes(newRoutes); 109632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } 110632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } 111632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn 112632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn void updateRoutes(AudioRoutesInfo newRoutes) { 113632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn if (newRoutes.mMainType != mCurRoutesInfo.mMainType) { 114632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn mCurRoutesInfo.mMainType = newRoutes.mMainType; 115632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn int name; 116632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn if ((newRoutes.mMainType&AudioRoutesInfo.MAIN_HEADPHONES) != 0 117632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn || (newRoutes.mMainType&AudioRoutesInfo.MAIN_HEADSET) != 0) { 118632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn name = com.android.internal.R.string.default_audio_route_name_headphones; 119632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } else if ((newRoutes.mMainType&AudioRoutesInfo.MAIN_DOCK_SPEAKERS) != 0) { 120632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn name = com.android.internal.R.string.default_audio_route_name_dock_speakers; 121632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } else if ((newRoutes.mMainType&AudioRoutesInfo.MAIN_HDMI) != 0) { 122632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn name = com.android.internal.R.string.default_audio_route_name_hdmi; 123632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } else { 124632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn name = com.android.internal.R.string.default_audio_route_name; 125632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } 126632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn sStatic.mDefaultAudio.mNameResId = name; 127632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn dispatchRouteChanged(sStatic.mDefaultAudio); 128632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } 129632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn if (!TextUtils.equals(newRoutes.mBluetoothName, mCurRoutesInfo.mBluetoothName)) { 130632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn mCurRoutesInfo.mBluetoothName = newRoutes.mBluetoothName; 131632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn if (mCurRoutesInfo.mBluetoothName != null) { 132632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn if (sStatic.mBluetoothA2dpRoute == null) { 133632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn final RouteInfo info = new RouteInfo(sStatic.mSystemCategory); 134632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn info.mName = mCurRoutesInfo.mBluetoothName; 135632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn info.mSupportedTypes = ROUTE_TYPE_LIVE_AUDIO; 136632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn sStatic.mBluetoothA2dpRoute = info; 137632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn addRoute(sStatic.mBluetoothA2dpRoute); 138dd0a19266d5c837069da1ea188744d54c8d723a8Adam Powell try { 139dd0a19266d5c837069da1ea188744d54c8d723a8Adam Powell if (mAudioService.isBluetoothA2dpOn()) { 140dd0a19266d5c837069da1ea188744d54c8d723a8Adam Powell selectRouteStatic(ROUTE_TYPE_LIVE_AUDIO, mBluetoothA2dpRoute); 141dd0a19266d5c837069da1ea188744d54c8d723a8Adam Powell } 142dd0a19266d5c837069da1ea188744d54c8d723a8Adam Powell } catch (RemoteException e) { 143dd0a19266d5c837069da1ea188744d54c8d723a8Adam Powell Log.e(TAG, "Error selecting Bluetooth A2DP route", e); 144dd0a19266d5c837069da1ea188744d54c8d723a8Adam Powell } 145632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } else { 146632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn sStatic.mBluetoothA2dpRoute.mName = mCurRoutesInfo.mBluetoothName; 147632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn dispatchRouteChanged(sStatic.mBluetoothA2dpRoute); 148632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } 149632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } else if (sStatic.mBluetoothA2dpRoute != null) { 150632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn removeRoute(sStatic.mBluetoothA2dpRoute); 151632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn sStatic.mBluetoothA2dpRoute = null; 152632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } 153632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } 154b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn } 155b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn } 1569a1de308cea2d160778fd977825f10a07b49d738Adam Powell 157b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn static Static sStatic; 1589a1de308cea2d160778fd977825f10a07b49d738Adam Powell 1599a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 1609a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Route type flag for live audio. 1619a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 1629a1de308cea2d160778fd977825f10a07b49d738Adam Powell * <p>A device that supports live audio routing will allow the media audio stream 1639a1de308cea2d160778fd977825f10a07b49d738Adam Powell * to be routed to supported destinations. This can include internal speakers or 1649a1de308cea2d160778fd977825f10a07b49d738Adam Powell * audio jacks on the device itself, A2DP devices, and more.</p> 1659a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 1669a1de308cea2d160778fd977825f10a07b49d738Adam Powell * <p>Once initiated this routing is transparent to the application. All audio 1679a1de308cea2d160778fd977825f10a07b49d738Adam Powell * played on the media stream will be routed to the selected destination.</p> 1689a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 1699a1de308cea2d160778fd977825f10a07b49d738Adam Powell public static final int ROUTE_TYPE_LIVE_AUDIO = 0x1; 1709a1de308cea2d160778fd977825f10a07b49d738Adam Powell 1719a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 1729a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Route type flag for application-specific usage. 1739a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 1749a1de308cea2d160778fd977825f10a07b49d738Adam Powell * <p>Unlike other media route types, user routes are managed by the application. 1759a1de308cea2d160778fd977825f10a07b49d738Adam Powell * The MediaRouter will manage and dispatch events for user routes, but the application 1769a1de308cea2d160778fd977825f10a07b49d738Adam Powell * is expected to interpret the meaning of these events and perform the requested 1779a1de308cea2d160778fd977825f10a07b49d738Adam Powell * routing tasks.</p> 1789a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 1799a1de308cea2d160778fd977825f10a07b49d738Adam Powell public static final int ROUTE_TYPE_USER = 0x00800000; 1809a1de308cea2d160778fd977825f10a07b49d738Adam Powell 1819a1de308cea2d160778fd977825f10a07b49d738Adam Powell // Maps application contexts 1829a1de308cea2d160778fd977825f10a07b49d738Adam Powell static final HashMap<Context, MediaRouter> sRouters = new HashMap<Context, MediaRouter>(); 1839a1de308cea2d160778fd977825f10a07b49d738Adam Powell 1849a1de308cea2d160778fd977825f10a07b49d738Adam Powell static String typesToString(int types) { 1859a1de308cea2d160778fd977825f10a07b49d738Adam Powell final StringBuilder result = new StringBuilder(); 1869a1de308cea2d160778fd977825f10a07b49d738Adam Powell if ((types & ROUTE_TYPE_LIVE_AUDIO) != 0) { 1879a1de308cea2d160778fd977825f10a07b49d738Adam Powell result.append("ROUTE_TYPE_LIVE_AUDIO "); 1889a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 1899a1de308cea2d160778fd977825f10a07b49d738Adam Powell if ((types & ROUTE_TYPE_USER) != 0) { 1909a1de308cea2d160778fd977825f10a07b49d738Adam Powell result.append("ROUTE_TYPE_USER "); 1919a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 1929a1de308cea2d160778fd977825f10a07b49d738Adam Powell return result.toString(); 1939a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 1949a1de308cea2d160778fd977825f10a07b49d738Adam Powell 195b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn /** @hide */ 196b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn public MediaRouter(Context context) { 197b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn synchronized (Static.class) { 198b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn if (sStatic == null) { 1998e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final Context appContext = context.getApplicationContext(); 2008e37a85bf3dc39519942698dc90a3951306b934bAdam Powell sStatic = new Static(appContext); 2018e37a85bf3dc39519942698dc90a3951306b934bAdam Powell sStatic.startMonitoringRoutes(appContext); 202b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn } 2039a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 2049a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 2059a1de308cea2d160778fd977825f10a07b49d738Adam Powell 206690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell /** 207690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell * @hide for use by framework routing UI 208690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell */ 209690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell public RouteInfo getSystemAudioRoute() { 210b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn return sStatic.mDefaultAudio; 211690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell } 212690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell 213690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell /** 2144599696591f745b3a546197d2ba7e5cfc5562484Adam Powell * @hide for use by framework routing UI 2154599696591f745b3a546197d2ba7e5cfc5562484Adam Powell */ 2164599696591f745b3a546197d2ba7e5cfc5562484Adam Powell public RouteCategory getSystemAudioCategory() { 2174599696591f745b3a546197d2ba7e5cfc5562484Adam Powell return sStatic.mSystemCategory; 2184599696591f745b3a546197d2ba7e5cfc5562484Adam Powell } 2194599696591f745b3a546197d2ba7e5cfc5562484Adam Powell 2204599696591f745b3a546197d2ba7e5cfc5562484Adam Powell /** 221690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell * Return the currently selected route for the given types 222690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell * 223690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell * @param type route types 224690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell * @return the selected route 225690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell */ 226690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell public RouteInfo getSelectedRoute(int type) { 227b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn return sStatic.mSelectedRoute; 228690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell } 229690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell 2309a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 2319a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Add a callback to listen to events about specific kinds of media routes. 2329a1de308cea2d160778fd977825f10a07b49d738Adam Powell * If the specified callback is already registered, its registration will be updated for any 2339a1de308cea2d160778fd977825f10a07b49d738Adam Powell * additional route types specified. 2349a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 2359a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param types Types of routes this callback is interested in 2369a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param cb Callback to add 2379a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 2389a1de308cea2d160778fd977825f10a07b49d738Adam Powell public void addCallback(int types, Callback cb) { 239b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn final int count = sStatic.mCallbacks.size(); 2409a1de308cea2d160778fd977825f10a07b49d738Adam Powell for (int i = 0; i < count; i++) { 241b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn final CallbackInfo info = sStatic.mCallbacks.get(i); 2429a1de308cea2d160778fd977825f10a07b49d738Adam Powell if (info.cb == cb) { 243dbbfa702a09f6d2d36dee1b552442d04a4673f89Adam Powell info.type |= types; 2449a1de308cea2d160778fd977825f10a07b49d738Adam Powell return; 2459a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 2469a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 247b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn sStatic.mCallbacks.add(new CallbackInfo(cb, types, this)); 2489a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 2499a1de308cea2d160778fd977825f10a07b49d738Adam Powell 2509a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 2519a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Remove the specified callback. It will no longer receive events about media routing. 2529a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 2539a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param cb Callback to remove 2549a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 2559a1de308cea2d160778fd977825f10a07b49d738Adam Powell public void removeCallback(Callback cb) { 256b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn final int count = sStatic.mCallbacks.size(); 2579a1de308cea2d160778fd977825f10a07b49d738Adam Powell for (int i = 0; i < count; i++) { 258b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn if (sStatic.mCallbacks.get(i).cb == cb) { 259b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn sStatic.mCallbacks.remove(i); 2609a1de308cea2d160778fd977825f10a07b49d738Adam Powell return; 2619a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 2629a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 2639a1de308cea2d160778fd977825f10a07b49d738Adam Powell Log.w(TAG, "removeCallback(" + cb + "): callback not registered"); 2649a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 2659a1de308cea2d160778fd977825f10a07b49d738Adam Powell 266d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell /** 267d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * Select the specified route to use for output of the given media types. 268d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * 269d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param types type flags indicating which types this route should be used for. 270d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * The route must support at least a subset. 271d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param route Route to select 272d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell */ 2739a1de308cea2d160778fd977825f10a07b49d738Adam Powell public void selectRoute(int types, RouteInfo route) { 2740d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell // Applications shouldn't programmatically change anything but user routes. 2750d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell types &= ROUTE_TYPE_USER; 2760d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell selectRouteStatic(types, route); 2770d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell } 2780d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell 2790d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell /** 2800d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * @hide internal use 2810d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell */ 2820d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public void selectRouteInt(int types, RouteInfo route) { 283b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn selectRouteStatic(types, route); 284b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn } 285b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn 286b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn static void selectRouteStatic(int types, RouteInfo route) { 287b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn if (sStatic.mSelectedRoute == route) return; 2880d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell if ((route.getSupportedTypes() & types) == 0) { 2890d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell Log.w(TAG, "selectRoute ignored; cannot select route with supported types " + 2900d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell typesToString(route.getSupportedTypes()) + " into route types " + 2910d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell typesToString(types)); 2924ee1f55ce0f4909a7430ab44563a81852f335071Adam Powell return; 2930d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell } 2949a1de308cea2d160778fd977825f10a07b49d738Adam Powell 295dd0a19266d5c837069da1ea188744d54c8d723a8Adam Powell final RouteInfo btRoute = sStatic.mBluetoothA2dpRoute; 296dd0a19266d5c837069da1ea188744d54c8d723a8Adam Powell if (btRoute != null && (types & ROUTE_TYPE_LIVE_AUDIO) != 0 && 297dd0a19266d5c837069da1ea188744d54c8d723a8Adam Powell (route == btRoute || route == sStatic.mDefaultAudio)) { 298dd0a19266d5c837069da1ea188744d54c8d723a8Adam Powell try { 299dd0a19266d5c837069da1ea188744d54c8d723a8Adam Powell sStatic.mAudioService.setBluetoothA2dpOn(route == btRoute); 300dd0a19266d5c837069da1ea188744d54c8d723a8Adam Powell } catch (RemoteException e) { 301dd0a19266d5c837069da1ea188744d54c8d723a8Adam Powell Log.e(TAG, "Error changing Bluetooth A2DP state", e); 302dd0a19266d5c837069da1ea188744d54c8d723a8Adam Powell } 303dd0a19266d5c837069da1ea188744d54c8d723a8Adam Powell } 304dd0a19266d5c837069da1ea188744d54c8d723a8Adam Powell 305b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn if (sStatic.mSelectedRoute != null) { 3069a1de308cea2d160778fd977825f10a07b49d738Adam Powell // TODO filter types properly 307b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn dispatchRouteUnselected(types & sStatic.mSelectedRoute.getSupportedTypes(), 308b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn sStatic.mSelectedRoute); 3099a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 310b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn sStatic.mSelectedRoute = route; 3119a1de308cea2d160778fd977825f10a07b49d738Adam Powell if (route != null) { 3129a1de308cea2d160778fd977825f10a07b49d738Adam Powell // TODO filter types properly 3139a1de308cea2d160778fd977825f10a07b49d738Adam Powell dispatchRouteSelected(types & route.getSupportedTypes(), route); 3149a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 3159a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 3169a1de308cea2d160778fd977825f10a07b49d738Adam Powell 3179a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 3189a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Add an app-specified route for media to the MediaRouter. 3199a1de308cea2d160778fd977825f10a07b49d738Adam Powell * App-specified route definitions are created using {@link #createUserRoute(RouteCategory)} 3209a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 3219a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param info Definition of the route to add 3229a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @see #createUserRoute() 3239a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @see #removeUserRoute(UserRouteInfo) 3249a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 3259a1de308cea2d160778fd977825f10a07b49d738Adam Powell public void addUserRoute(UserRouteInfo info) { 3269a1de308cea2d160778fd977825f10a07b49d738Adam Powell addRoute(info); 3279a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 3289a1de308cea2d160778fd977825f10a07b49d738Adam Powell 329d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell /** 330d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell * @hide Framework use only 331d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell */ 332d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell public void addRouteInt(RouteInfo info) { 333d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell addRoute(info); 334d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell } 335d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell 336b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn static void addRoute(RouteInfo info) { 3379a1de308cea2d160778fd977825f10a07b49d738Adam Powell final RouteCategory cat = info.getCategory(); 338b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn if (!sStatic.mCategories.contains(cat)) { 339b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn sStatic.mCategories.add(cat); 3409a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 341b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn final boolean onlyRoute = sStatic.mRoutes.isEmpty(); 342d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell if (cat.isGroupable() && !(info instanceof RouteGroup)) { 3439a1de308cea2d160778fd977825f10a07b49d738Adam Powell // Enforce that any added route in a groupable category must be in a group. 3449a1de308cea2d160778fd977825f10a07b49d738Adam Powell final RouteGroup group = new RouteGroup(info.getCategory()); 345dbbfa702a09f6d2d36dee1b552442d04a4673f89Adam Powell group.mSupportedTypes = info.mSupportedTypes; 346b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn sStatic.mRoutes.add(group); 347d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell dispatchRouteAdded(group); 348b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell group.addRoute(info); 349d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell 3509a1de308cea2d160778fd977825f10a07b49d738Adam Powell info = group; 351d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell } else { 352b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn sStatic.mRoutes.add(info); 353d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell dispatchRouteAdded(info); 3549a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 355d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell 3569a1de308cea2d160778fd977825f10a07b49d738Adam Powell if (onlyRoute) { 357b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn selectRouteStatic(info.getSupportedTypes(), info); 3589a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 3599a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 3609a1de308cea2d160778fd977825f10a07b49d738Adam Powell 3619a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 3629a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Remove an app-specified route for media from the MediaRouter. 3639a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 3649a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param info Definition of the route to remove 3659a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @see #addUserRoute(UserRouteInfo) 3669a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 3679a1de308cea2d160778fd977825f10a07b49d738Adam Powell public void removeUserRoute(UserRouteInfo info) { 3689a1de308cea2d160778fd977825f10a07b49d738Adam Powell removeRoute(info); 3699a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 3709a1de308cea2d160778fd977825f10a07b49d738Adam Powell 371690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell /** 372690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell * Remove all app-specified routes from the MediaRouter. 373690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell * 374690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell * @see #removeUserRoute(UserRouteInfo) 375690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell */ 376690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell public void clearUserRoutes() { 377b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn for (int i = 0; i < sStatic.mRoutes.size(); i++) { 378b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn final RouteInfo info = sStatic.mRoutes.get(i); 379d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell // TODO Right now, RouteGroups only ever contain user routes. 380d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell // The code below will need to change if this assumption does. 381d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell if (info instanceof UserRouteInfo || info instanceof RouteGroup) { 382690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell removeRouteAt(i); 383690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell i--; 384690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell } 385690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell } 386690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell } 387690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell 388d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell /** 389d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell * @hide internal use only 390d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell */ 391d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell public void removeRouteInt(RouteInfo info) { 392d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell removeRoute(info); 393d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell } 394d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell 395b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn static void removeRoute(RouteInfo info) { 396b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn if (sStatic.mRoutes.remove(info)) { 3979a1de308cea2d160778fd977825f10a07b49d738Adam Powell final RouteCategory removingCat = info.getCategory(); 398b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn final int count = sStatic.mRoutes.size(); 3999a1de308cea2d160778fd977825f10a07b49d738Adam Powell boolean found = false; 4009a1de308cea2d160778fd977825f10a07b49d738Adam Powell for (int i = 0; i < count; i++) { 401b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn final RouteCategory cat = sStatic.mRoutes.get(i).getCategory(); 4029a1de308cea2d160778fd977825f10a07b49d738Adam Powell if (removingCat == cat) { 4039a1de308cea2d160778fd977825f10a07b49d738Adam Powell found = true; 4049a1de308cea2d160778fd977825f10a07b49d738Adam Powell break; 4059a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 4069a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 407d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell if (info == sStatic.mSelectedRoute) { 408d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell // Removing the currently selected route? Select the default before we remove it. 409d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell // TODO: Be smarter about the route types here; this selects for all valid. 410d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell selectRouteStatic(ROUTE_TYPE_LIVE_AUDIO | ROUTE_TYPE_USER, sStatic.mDefaultAudio); 411d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell } 4129a1de308cea2d160778fd977825f10a07b49d738Adam Powell if (!found) { 413b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn sStatic.mCategories.remove(removingCat); 4149a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 4159a1de308cea2d160778fd977825f10a07b49d738Adam Powell dispatchRouteRemoved(info); 4169a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 4179a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 4189a1de308cea2d160778fd977825f10a07b49d738Adam Powell 419690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell void removeRouteAt(int routeIndex) { 420b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn if (routeIndex >= 0 && routeIndex < sStatic.mRoutes.size()) { 421b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn final RouteInfo info = sStatic.mRoutes.remove(routeIndex); 422690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell final RouteCategory removingCat = info.getCategory(); 423b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn final int count = sStatic.mRoutes.size(); 424690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell boolean found = false; 425690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell for (int i = 0; i < count; i++) { 426b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn final RouteCategory cat = sStatic.mRoutes.get(i).getCategory(); 427690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell if (removingCat == cat) { 428690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell found = true; 429690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell break; 430690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell } 431690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell } 432d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell if (info == sStatic.mSelectedRoute) { 433d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell // Removing the currently selected route? Select the default before we remove it. 434d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell // TODO: Be smarter about the route types here; this selects for all valid. 435d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell selectRouteStatic(ROUTE_TYPE_LIVE_AUDIO | ROUTE_TYPE_USER, sStatic.mDefaultAudio); 436d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell } 437690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell if (!found) { 438b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn sStatic.mCategories.remove(removingCat); 439690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell } 440690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell dispatchRouteRemoved(info); 441690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell } 442690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell } 443690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell 4449a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 4459a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Return the number of {@link MediaRouter.RouteCategory categories} currently 4469a1de308cea2d160778fd977825f10a07b49d738Adam Powell * represented by routes known to this MediaRouter. 4479a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 4489a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @return the number of unique categories represented by this MediaRouter's known routes 4499a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 4509a1de308cea2d160778fd977825f10a07b49d738Adam Powell public int getCategoryCount() { 451b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn return sStatic.mCategories.size(); 4529a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 4539a1de308cea2d160778fd977825f10a07b49d738Adam Powell 4549a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 4559a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Return the {@link MediaRouter.RouteCategory category} at the given index. 4569a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Valid indices are in the range [0-getCategoryCount). 4579a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 4589a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param index which category to return 4599a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @return the category at index 4609a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 4619a1de308cea2d160778fd977825f10a07b49d738Adam Powell public RouteCategory getCategoryAt(int index) { 462b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn return sStatic.mCategories.get(index); 4639a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 4649a1de308cea2d160778fd977825f10a07b49d738Adam Powell 4659a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 4669a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Return the number of {@link MediaRouter.RouteInfo routes} currently known 4679a1de308cea2d160778fd977825f10a07b49d738Adam Powell * to this MediaRouter. 4689a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 4699a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @return the number of routes tracked by this router 4709a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 4719a1de308cea2d160778fd977825f10a07b49d738Adam Powell public int getRouteCount() { 472b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn return sStatic.mRoutes.size(); 4739a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 4749a1de308cea2d160778fd977825f10a07b49d738Adam Powell 4759a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 4769a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Return the route at the specified index. 4779a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 4789a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param index index of the route to return 4799a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @return the route at index 4809a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 4819a1de308cea2d160778fd977825f10a07b49d738Adam Powell public RouteInfo getRouteAt(int index) { 482b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn return sStatic.mRoutes.get(index); 483b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn } 484b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn 485b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn static int getRouteCountStatic() { 486b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn return sStatic.mRoutes.size(); 487b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn } 488b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn 489b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn static RouteInfo getRouteAtStatic(int index) { 490b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn return sStatic.mRoutes.get(index); 4919a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 4929a1de308cea2d160778fd977825f10a07b49d738Adam Powell 4939a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 4949a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Create a new user route that may be modified and registered for use by the application. 4959a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 4969a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param category The category the new route will belong to 4979a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @return A new UserRouteInfo for use by the application 4989a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 4999a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @see #addUserRoute(UserRouteInfo) 5009a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @see #removeUserRoute(UserRouteInfo) 5019a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @see #createRouteCategory(CharSequence) 5029a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 5039a1de308cea2d160778fd977825f10a07b49d738Adam Powell public UserRouteInfo createUserRoute(RouteCategory category) { 5049a1de308cea2d160778fd977825f10a07b49d738Adam Powell return new UserRouteInfo(category); 5059a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 5069a1de308cea2d160778fd977825f10a07b49d738Adam Powell 5079a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 5089a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Create a new route category. Each route must belong to a category. 5099a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 5109a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param name Name of the new category 5119a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param isGroupable true if routes in this category may be grouped with one another 5129a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @return the new RouteCategory 5139a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 5149a1de308cea2d160778fd977825f10a07b49d738Adam Powell public RouteCategory createRouteCategory(CharSequence name, boolean isGroupable) { 5159a1de308cea2d160778fd977825f10a07b49d738Adam Powell return new RouteCategory(name, ROUTE_TYPE_USER, isGroupable); 5169a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 5170d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell 5180d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell /** 5190d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * Create a new route category. Each route must belong to a category. 5200d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * 5210d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * @param nameResId Resource ID of the name of the new category 5220d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * @param isGroupable true if routes in this category may be grouped with one another 5230d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * @return the new RouteCategory 5240d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell */ 5250d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public RouteCategory createRouteCategory(int nameResId, boolean isGroupable) { 5260d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell return new RouteCategory(nameResId, ROUTE_TYPE_USER, isGroupable); 5270d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell } 5289a1de308cea2d160778fd977825f10a07b49d738Adam Powell 529b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn static void updateRoute(final RouteInfo info) { 5309a1de308cea2d160778fd977825f10a07b49d738Adam Powell dispatchRouteChanged(info); 5319a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 5329a1de308cea2d160778fd977825f10a07b49d738Adam Powell 533b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn static void dispatchRouteSelected(int type, RouteInfo info) { 53439d5c6172503620ac3761148adac5fd7fa20d02dAdam Powell for (CallbackInfo cbi : sStatic.mCallbacks) { 5359a1de308cea2d160778fd977825f10a07b49d738Adam Powell if ((cbi.type & type) != 0) { 536b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn cbi.cb.onRouteSelected(cbi.router, type, info); 5379a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 5389a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 5399a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 5409a1de308cea2d160778fd977825f10a07b49d738Adam Powell 541b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn static void dispatchRouteUnselected(int type, RouteInfo info) { 54239d5c6172503620ac3761148adac5fd7fa20d02dAdam Powell for (CallbackInfo cbi : sStatic.mCallbacks) { 5439a1de308cea2d160778fd977825f10a07b49d738Adam Powell if ((cbi.type & type) != 0) { 544b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn cbi.cb.onRouteUnselected(cbi.router, type, info); 5459a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 5469a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 5479a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 5489a1de308cea2d160778fd977825f10a07b49d738Adam Powell 549b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn static void dispatchRouteChanged(RouteInfo info) { 55039d5c6172503620ac3761148adac5fd7fa20d02dAdam Powell for (CallbackInfo cbi : sStatic.mCallbacks) { 5519a1de308cea2d160778fd977825f10a07b49d738Adam Powell if ((cbi.type & info.mSupportedTypes) != 0) { 552b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn cbi.cb.onRouteChanged(cbi.router, info); 5539a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 5549a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 5559a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 5569a1de308cea2d160778fd977825f10a07b49d738Adam Powell 557b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn static void dispatchRouteAdded(RouteInfo info) { 55839d5c6172503620ac3761148adac5fd7fa20d02dAdam Powell for (CallbackInfo cbi : sStatic.mCallbacks) { 5599a1de308cea2d160778fd977825f10a07b49d738Adam Powell if ((cbi.type & info.mSupportedTypes) != 0) { 560b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn cbi.cb.onRouteAdded(cbi.router, info); 5619a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 5629a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 5639a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 5649a1de308cea2d160778fd977825f10a07b49d738Adam Powell 565b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn static void dispatchRouteRemoved(RouteInfo info) { 56639d5c6172503620ac3761148adac5fd7fa20d02dAdam Powell for (CallbackInfo cbi : sStatic.mCallbacks) { 5679a1de308cea2d160778fd977825f10a07b49d738Adam Powell if ((cbi.type & info.mSupportedTypes) != 0) { 568b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn cbi.cb.onRouteRemoved(cbi.router, info); 5699a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 5709a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 5719a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 5729a1de308cea2d160778fd977825f10a07b49d738Adam Powell 573b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn static void dispatchRouteGrouped(RouteInfo info, RouteGroup group, int index) { 57439d5c6172503620ac3761148adac5fd7fa20d02dAdam Powell for (CallbackInfo cbi : sStatic.mCallbacks) { 575d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell if ((cbi.type & group.mSupportedTypes) != 0) { 576b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn cbi.cb.onRouteGrouped(cbi.router, info, group, index); 577d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell } 578d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell } 579d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell } 580d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell 581b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn static void dispatchRouteUngrouped(RouteInfo info, RouteGroup group) { 58239d5c6172503620ac3761148adac5fd7fa20d02dAdam Powell for (CallbackInfo cbi : sStatic.mCallbacks) { 583d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell if ((cbi.type & group.mSupportedTypes) != 0) { 584b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn cbi.cb.onRouteUngrouped(cbi.router, info, group); 5859a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 5869a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 5879a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 5889a1de308cea2d160778fd977825f10a07b49d738Adam Powell 5898e37a85bf3dc39519942698dc90a3951306b934bAdam Powell static void dispatchRouteVolumeChanged(RouteInfo info) { 5908e37a85bf3dc39519942698dc90a3951306b934bAdam Powell for (CallbackInfo cbi : sStatic.mCallbacks) { 5918e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if ((cbi.type & info.mSupportedTypes) != 0) { 5928e37a85bf3dc39519942698dc90a3951306b934bAdam Powell cbi.cb.onRouteVolumeChanged(cbi.router, info); 5938e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 5948e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 5958e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 5968e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 5978e37a85bf3dc39519942698dc90a3951306b934bAdam Powell static void systemVolumeChanged(int newValue) { 5988e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final RouteInfo selectedRoute = sStatic.mSelectedRoute; 5998e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (selectedRoute == null) return; 6008e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 6018e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (selectedRoute == sStatic.mBluetoothA2dpRoute || 6028e37a85bf3dc39519942698dc90a3951306b934bAdam Powell selectedRoute == sStatic.mDefaultAudio) { 6038e37a85bf3dc39519942698dc90a3951306b934bAdam Powell dispatchRouteVolumeChanged(selectedRoute); 6048e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } else if (sStatic.mBluetoothA2dpRoute != null) { 6058e37a85bf3dc39519942698dc90a3951306b934bAdam Powell try { 6068e37a85bf3dc39519942698dc90a3951306b934bAdam Powell dispatchRouteVolumeChanged(sStatic.mAudioService.isBluetoothA2dpOn() ? 6078e37a85bf3dc39519942698dc90a3951306b934bAdam Powell sStatic.mBluetoothA2dpRoute : sStatic.mDefaultAudio); 6088e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } catch (RemoteException e) { 6098e37a85bf3dc39519942698dc90a3951306b934bAdam Powell Log.e(TAG, "Error checking Bluetooth A2DP state to report volume change", e); 6108e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 6118e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } else { 6128e37a85bf3dc39519942698dc90a3951306b934bAdam Powell dispatchRouteVolumeChanged(sStatic.mDefaultAudio); 6138e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 6148e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 6158e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 6169a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 6179a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Information about a media route. 6189a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 619b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn public static class RouteInfo { 6209a1de308cea2d160778fd977825f10a07b49d738Adam Powell CharSequence mName; 6210d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell int mNameResId; 6229a1de308cea2d160778fd977825f10a07b49d738Adam Powell private CharSequence mStatus; 6239a1de308cea2d160778fd977825f10a07b49d738Adam Powell int mSupportedTypes; 6249a1de308cea2d160778fd977825f10a07b49d738Adam Powell RouteGroup mGroup; 6259a1de308cea2d160778fd977825f10a07b49d738Adam Powell final RouteCategory mCategory; 626ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell Drawable mIcon; 6271357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi // playback information 6281357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi int mPlaybackType = PLAYBACK_TYPE_LOCAL; 6291357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi int mVolumeMax = RemoteControlClient.DEFAULT_PLAYBACK_VOLUME; 6301357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi int mVolume = RemoteControlClient.DEFAULT_PLAYBACK_VOLUME; 6311357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi int mVolumeHandling = RemoteControlClient.DEFAULT_PLAYBACK_VOLUME_HANDLING; 6321357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi int mPlaybackStream = AudioManager.STREAM_MUSIC; 6331357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi VolumeCallbackInfo mVcb; 6349a1de308cea2d160778fd977825f10a07b49d738Adam Powell 635b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell private Object mTag; 636b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell 6371357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 6381357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * The default playback type, "local", indicating the presentation of the media is happening 6391357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * on the same device (e.g. a phone, a tablet) as where it is controlled from. 6401357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @see #setPlaybackType(int) 6411357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 6421357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public final static int PLAYBACK_TYPE_LOCAL = 0; 6431357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 6441357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * A playback type indicating the presentation of the media is happening on 6451357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * a different device (i.e. the remote device) than where it is controlled from. 6461357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @see #setPlaybackType(int) 6471357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 6481357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public final static int PLAYBACK_TYPE_REMOTE = 1; 6491357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 6501357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * Playback information indicating the playback volume is fixed, i.e. it cannot be 6511357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * controlled from this object. An example of fixed playback volume is a remote player, 6521357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * playing over HDMI where the user prefers to control the volume on the HDMI sink, rather 6531357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * than attenuate at the source. 6541357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @see #setVolumeHandling(int) 6551357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 6561357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public final static int PLAYBACK_VOLUME_FIXED = 0; 6571357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 6581357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * Playback information indicating the playback volume is variable and can be controlled 6591357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * from this object. 6601357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 6611357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public final static int PLAYBACK_VOLUME_VARIABLE = 1; 6621357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 6639a1de308cea2d160778fd977825f10a07b49d738Adam Powell RouteInfo(RouteCategory category) { 6649a1de308cea2d160778fd977825f10a07b49d738Adam Powell mCategory = category; 6659a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 6669a1de308cea2d160778fd977825f10a07b49d738Adam Powell 6679a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 6689a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @return The user-friendly name of a media route. This is the string presented 6699a1de308cea2d160778fd977825f10a07b49d738Adam Powell * to users who may select this as the active route. 6709a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 6719a1de308cea2d160778fd977825f10a07b49d738Adam Powell public CharSequence getName() { 6720d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell return getName(sStatic.mResources); 6730d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell } 6740d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell 6750d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell /** 6760d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * Return the properly localized/resource selected name of this route. 6770d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * 6780d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * @param context Context used to resolve the correct configuration to load 6790d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * @return The user-friendly name of the media route. This is the string presented 6800d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * to users who may select this as the active route. 6810d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell */ 6820d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public CharSequence getName(Context context) { 6830d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell return getName(context.getResources()); 6840d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell } 6850d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell 6860d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell CharSequence getName(Resources res) { 6870d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell if (mNameResId != 0) { 6880d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell return mName = res.getText(mNameResId); 6890d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell } 6909a1de308cea2d160778fd977825f10a07b49d738Adam Powell return mName; 6919a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 6929a1de308cea2d160778fd977825f10a07b49d738Adam Powell 6939a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 6949a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @return The user-friendly status for a media route. This may include a description 6959a1de308cea2d160778fd977825f10a07b49d738Adam Powell * of the currently playing media, if available. 6969a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 6979a1de308cea2d160778fd977825f10a07b49d738Adam Powell public CharSequence getStatus() { 6989a1de308cea2d160778fd977825f10a07b49d738Adam Powell return mStatus; 6999a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 7009a1de308cea2d160778fd977825f10a07b49d738Adam Powell 7019a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 7029a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @return A media type flag set describing which types this route supports. 7039a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 7049a1de308cea2d160778fd977825f10a07b49d738Adam Powell public int getSupportedTypes() { 7059a1de308cea2d160778fd977825f10a07b49d738Adam Powell return mSupportedTypes; 7069a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 7079a1de308cea2d160778fd977825f10a07b49d738Adam Powell 7089a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 7099a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @return The group that this route belongs to. 7109a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 7119a1de308cea2d160778fd977825f10a07b49d738Adam Powell public RouteGroup getGroup() { 7129a1de308cea2d160778fd977825f10a07b49d738Adam Powell return mGroup; 7139a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 7149a1de308cea2d160778fd977825f10a07b49d738Adam Powell 7159a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 7169a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @return the category this route belongs to. 7179a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 7189a1de308cea2d160778fd977825f10a07b49d738Adam Powell public RouteCategory getCategory() { 7199a1de308cea2d160778fd977825f10a07b49d738Adam Powell return mCategory; 7209a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 7219a1de308cea2d160778fd977825f10a07b49d738Adam Powell 722ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell /** 723ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * Get the icon representing this route. 724ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * This icon will be used in picker UIs if available. 725ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * 726ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * @return the icon representing this route or null if no icon is available 727ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell */ 728ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell public Drawable getIconDrawable() { 729ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell return mIcon; 730ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell } 731ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell 732b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell /** 733b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell * Set an application-specific tag object for this route. 734b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell * The application may use this to store arbitrary data associated with the 735b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell * route for internal tracking. 736b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell * 737b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell * <p>Note that the lifespan of a route may be well past the lifespan of 738b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell * an Activity or other Context; take care that objects you store here 739b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell * will not keep more data in memory alive than you intend.</p> 740b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell * 741b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell * @param tag Arbitrary, app-specific data for this route to hold for later use 742b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell */ 743b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell public void setTag(Object tag) { 744b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell mTag = tag; 745130b4572d1f3df702e5b296a655d15a41f6d4c66Adam Powell routeUpdated(); 746b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell } 747b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell 748b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell /** 749b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell * @return The tag object previously set by the application 750b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell * @see #setTag(Object) 751b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell */ 752b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell public Object getTag() { 753b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell return mTag; 754b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell } 755b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell 7561357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 7571357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @return the type of playback associated with this route 7581357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @see UserRouteInfo#setPlaybackType(int) 7591357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 7601357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public int getPlaybackType() { 7611357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi return mPlaybackType; 7621357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 7631357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 7641357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 7651357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @return the stream over which the playback associated with this route is performed 7661357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @see UserRouteInfo#setPlaybackStream(int) 7671357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 7681357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public int getPlaybackStream() { 7691357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi return mPlaybackStream; 7701357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 7711357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 7721357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 7738e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * Return the current volume for this route. Depending on the route, this may only 7748e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * be valid if the route is currently selected. 7758e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * 7761357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @return the volume at which the playback associated with this route is performed 7771357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @see UserRouteInfo#setVolume(int) 7781357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 7791357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public int getVolume() { 7801357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi if (mPlaybackType == PLAYBACK_TYPE_LOCAL) { 7811357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi int vol = 0; 7821357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi try { 7831357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi vol = sStatic.mAudioService.getStreamVolume(mPlaybackStream); 7841357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } catch (RemoteException e) { 7851357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi Log.e(TAG, "Error getting local stream volume", e); 7861357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 7871357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi return vol; 7881357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } else { 7891357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi return mVolume; 7901357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 7911357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 7921357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 7931357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 7948e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * Request a volume change for this route. 7958e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * @param volume value between 0 and getVolumeMax 7968e37a85bf3dc39519942698dc90a3951306b934bAdam Powell */ 7978e37a85bf3dc39519942698dc90a3951306b934bAdam Powell public void requestSetVolume(int volume) { 7988e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (mPlaybackType == PLAYBACK_TYPE_LOCAL) { 7998e37a85bf3dc39519942698dc90a3951306b934bAdam Powell try { 8008e37a85bf3dc39519942698dc90a3951306b934bAdam Powell sStatic.mAudioService.setStreamVolume(mPlaybackStream, volume, 0); 8018e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } catch (RemoteException e) { 8028e37a85bf3dc39519942698dc90a3951306b934bAdam Powell Log.e(TAG, "Error setting local stream volume", e); 8038e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 8048e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } else { 8058e37a85bf3dc39519942698dc90a3951306b934bAdam Powell Log.e(TAG, getClass().getSimpleName() + ".requestSetVolume(): " + 8068e37a85bf3dc39519942698dc90a3951306b934bAdam Powell "Non-local volume playback on system route? " + 8078e37a85bf3dc39519942698dc90a3951306b934bAdam Powell "Could not request volume change."); 8088e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 8098e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 8108e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 8118e37a85bf3dc39519942698dc90a3951306b934bAdam Powell /** 8128e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * Request an incremental volume update for this route. 8138e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * @param direction Delta to apply to the current volume 8148e37a85bf3dc39519942698dc90a3951306b934bAdam Powell */ 8158e37a85bf3dc39519942698dc90a3951306b934bAdam Powell public void requestUpdateVolume(int direction) { 8168e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (mPlaybackType == PLAYBACK_TYPE_LOCAL) { 8178e37a85bf3dc39519942698dc90a3951306b934bAdam Powell try { 8188e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final int volume = 8198e37a85bf3dc39519942698dc90a3951306b934bAdam Powell Math.max(0, Math.min(getVolume() + direction, getVolumeMax())); 8208e37a85bf3dc39519942698dc90a3951306b934bAdam Powell sStatic.mAudioService.setStreamVolume(mPlaybackStream, volume, 0); 8218e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } catch (RemoteException e) { 8228e37a85bf3dc39519942698dc90a3951306b934bAdam Powell Log.e(TAG, "Error setting local stream volume", e); 8238e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 8248e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } else { 8258e37a85bf3dc39519942698dc90a3951306b934bAdam Powell Log.e(TAG, getClass().getSimpleName() + ".requestChangeVolume(): " + 8268e37a85bf3dc39519942698dc90a3951306b934bAdam Powell "Non-local volume playback on system route? " + 8278e37a85bf3dc39519942698dc90a3951306b934bAdam Powell "Could not request volume change."); 8288e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 8298e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 8308e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 8318e37a85bf3dc39519942698dc90a3951306b934bAdam Powell /** 8321357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @return the maximum volume at which the playback associated with this route is performed 8331357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @see UserRouteInfo#setVolumeMax(int) 8341357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 8351357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public int getVolumeMax() { 8361357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi if (mPlaybackType == PLAYBACK_TYPE_LOCAL) { 8371357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi int volMax = 0; 8381357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi try { 8391357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi volMax = sStatic.mAudioService.getStreamMaxVolume(mPlaybackStream); 8401357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } catch (RemoteException e) { 8411357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi Log.e(TAG, "Error getting local stream volume", e); 8421357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 8431357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi return volMax; 8441357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } else { 8451357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi return mVolumeMax; 8461357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 8471357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 8481357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 8491357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 8501357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @return how volume is handling on the route 8511357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @see UserRouteInfo#setVolumeHandling(int) 8521357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 8531357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public int getVolumeHandling() { 8541357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi return mVolumeHandling; 8551357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 8561357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 8579a1de308cea2d160778fd977825f10a07b49d738Adam Powell void setStatusInt(CharSequence status) { 8589a1de308cea2d160778fd977825f10a07b49d738Adam Powell if (!status.equals(mStatus)) { 8599a1de308cea2d160778fd977825f10a07b49d738Adam Powell mStatus = status; 8609a1de308cea2d160778fd977825f10a07b49d738Adam Powell if (mGroup != null) { 8619a1de308cea2d160778fd977825f10a07b49d738Adam Powell mGroup.memberStatusChanged(this, status); 8629a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 8639a1de308cea2d160778fd977825f10a07b49d738Adam Powell routeUpdated(); 8649a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 8659a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 8669a1de308cea2d160778fd977825f10a07b49d738Adam Powell 8671357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi final IRemoteVolumeObserver.Stub mRemoteVolObserver = new IRemoteVolumeObserver.Stub() { 8681357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public void dispatchRemoteVolumeUpdate(final int direction, final int value) { 8691357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi sStatic.mHandler.post(new Runnable() { 8701357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi @Override 8711357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public void run() { 8721357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi //Log.d(TAG, "dispatchRemoteVolumeUpdate dir=" + direction + " val=" + value); 8731357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi if (mVcb != null) { 8741357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi if (direction != 0) { 8751357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi mVcb.vcb.onVolumeUpdateRequest(mVcb.route, direction); 8761357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } else { 8771357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi mVcb.vcb.onVolumeSetRequest(mVcb.route, value); 8781357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 8791357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 8801357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 8811357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi }); 8821357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 8831357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi }; 8841357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 8859a1de308cea2d160778fd977825f10a07b49d738Adam Powell void routeUpdated() { 8869a1de308cea2d160778fd977825f10a07b49d738Adam Powell updateRoute(this); 8879a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 8889a1de308cea2d160778fd977825f10a07b49d738Adam Powell 8899a1de308cea2d160778fd977825f10a07b49d738Adam Powell @Override 8909a1de308cea2d160778fd977825f10a07b49d738Adam Powell public String toString() { 891d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell String supportedTypes = typesToString(getSupportedTypes()); 892d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell return getClass().getSimpleName() + "{ name=" + getName() + ", status=" + getStatus() + 893d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell " category=" + getCategory() + 8949a1de308cea2d160778fd977825f10a07b49d738Adam Powell " supportedTypes=" + supportedTypes + "}"; 8959a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 8969a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 8979a1de308cea2d160778fd977825f10a07b49d738Adam Powell 8989a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 8999a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Information about a route that the application may define and modify. 9008e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * A user route defaults to {@link RouteInfo#PLAYBACK_TYPE_REMOTE} and 9018e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * {@link RouteInfo#PLAYBACK_VOLUME_FIXED}. 9029a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 9039a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @see MediaRouter.RouteInfo 9049a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 905b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn public static class UserRouteInfo extends RouteInfo { 906ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell RemoteControlClient mRcc; 9079a1de308cea2d160778fd977825f10a07b49d738Adam Powell 9089a1de308cea2d160778fd977825f10a07b49d738Adam Powell UserRouteInfo(RouteCategory category) { 9099a1de308cea2d160778fd977825f10a07b49d738Adam Powell super(category); 9109a1de308cea2d160778fd977825f10a07b49d738Adam Powell mSupportedTypes = ROUTE_TYPE_USER; 9118e37a85bf3dc39519942698dc90a3951306b934bAdam Powell mPlaybackType = PLAYBACK_TYPE_REMOTE; 9128e37a85bf3dc39519942698dc90a3951306b934bAdam Powell mVolumeHandling = PLAYBACK_VOLUME_FIXED; 9139a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 9149a1de308cea2d160778fd977825f10a07b49d738Adam Powell 9159a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 9169a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Set the user-visible name of this route. 9179a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param name Name to display to the user to describe this route 9189a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 9199a1de308cea2d160778fd977825f10a07b49d738Adam Powell public void setName(CharSequence name) { 9209a1de308cea2d160778fd977825f10a07b49d738Adam Powell mName = name; 9219a1de308cea2d160778fd977825f10a07b49d738Adam Powell routeUpdated(); 9229a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 9230d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell 9240d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell /** 9250d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * Set the user-visible name of this route. 9260d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * @param resId Resource ID of the name to display to the user to describe this route 9270d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell */ 9280d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public void setName(int resId) { 9290d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell mNameResId = resId; 9300d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell mName = null; 9310d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell routeUpdated(); 9320d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell } 9339a1de308cea2d160778fd977825f10a07b49d738Adam Powell 9349a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 9359a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Set the current user-visible status for this route. 9369a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param status Status to display to the user to describe what the endpoint 9379a1de308cea2d160778fd977825f10a07b49d738Adam Powell * of this route is currently doing 9389a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 9399a1de308cea2d160778fd977825f10a07b49d738Adam Powell public void setStatus(CharSequence status) { 9409a1de308cea2d160778fd977825f10a07b49d738Adam Powell setStatusInt(status); 9419a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 942ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell 943ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell /** 944ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * Set the RemoteControlClient responsible for reporting playback info for this 945ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * user route. 946ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * 947ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * <p>If this route manages remote playback, the data exposed by this 948ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * RemoteControlClient will be used to reflect and update information 949ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * such as route volume info in related UIs.</p> 950ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * 9511357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * <p>The RemoteControlClient must have been previously registered with 9521357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * {@link AudioManager#registerRemoteControlClient(RemoteControlClient)}.</p> 9531357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * 954ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * @param rcc RemoteControlClient associated with this route 955ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell */ 956ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell public void setRemoteControlClient(RemoteControlClient rcc) { 957ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell mRcc = rcc; 9581357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi updatePlaybackInfoOnRcc(); 959ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell } 960ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell 961ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell /** 9624599696591f745b3a546197d2ba7e5cfc5562484Adam Powell * Retrieve the RemoteControlClient associated with this route, if one has been set. 9634599696591f745b3a546197d2ba7e5cfc5562484Adam Powell * 9644599696591f745b3a546197d2ba7e5cfc5562484Adam Powell * @return the RemoteControlClient associated with this route 9654599696591f745b3a546197d2ba7e5cfc5562484Adam Powell * @see #setRemoteControlClient(RemoteControlClient) 9664599696591f745b3a546197d2ba7e5cfc5562484Adam Powell */ 9674599696591f745b3a546197d2ba7e5cfc5562484Adam Powell public RemoteControlClient getRemoteControlClient() { 9684599696591f745b3a546197d2ba7e5cfc5562484Adam Powell return mRcc; 9694599696591f745b3a546197d2ba7e5cfc5562484Adam Powell } 9704599696591f745b3a546197d2ba7e5cfc5562484Adam Powell 9714599696591f745b3a546197d2ba7e5cfc5562484Adam Powell /** 972ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * Set an icon that will be used to represent this route. 973ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * The system may use this icon in picker UIs or similar. 974ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * 975ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * @param icon icon drawable to use to represent this route 976ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell */ 977ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell public void setIconDrawable(Drawable icon) { 978ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell mIcon = icon; 979ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell } 980ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell 981ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell /** 982ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * Set an icon that will be used to represent this route. 983ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * The system may use this icon in picker UIs or similar. 984ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * 98571c69897ad0a55d590698bfa399bfe99c763b9dbAdam Powell * @param resId Resource ID of an icon drawable to use to represent this route 986ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell */ 987ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell public void setIconResource(int resId) { 988ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell setIconDrawable(sStatic.mResources.getDrawable(resId)); 989ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell } 9901357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 9911357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 9921357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * Set a callback to be notified of volume update requests 9931357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @param vcb 9941357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 9951357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public void setVolumeCallback(VolumeCallback vcb) { 9961357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi mVcb = new VolumeCallbackInfo(vcb, this); 9971357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 9981357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 9991357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 10001357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * Defines whether playback associated with this route is "local" 10011357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * ({@link RouteInfo#PLAYBACK_TYPE_LOCAL}) or "remote" 10021357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * ({@link RouteInfo#PLAYBACK_TYPE_REMOTE}). 10031357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @param type 10041357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 10051357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public void setPlaybackType(int type) { 10061357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi if (mPlaybackType != type) { 10071357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi mPlaybackType = type; 10081357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi setPlaybackInfoOnRcc(RemoteControlClient.PLAYBACKINFO_PLAYBACK_TYPE, type); 10091357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 10101357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 10111357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 10121357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 10131357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * Defines whether volume for the playback associated with this route is fixed 10141357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * ({@link RouteInfo#PLAYBACK_VOLUME_FIXED}) or can modified 10151357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * ({@link RouteInfo#PLAYBACK_VOLUME_VARIABLE}). 10161357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @param volumeHandling 10171357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 10181357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public void setVolumeHandling(int volumeHandling) { 10191357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi if (mVolumeHandling != volumeHandling) { 10201357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi mVolumeHandling = volumeHandling; 10211357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi setPlaybackInfoOnRcc( 10221357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi RemoteControlClient.PLAYBACKINFO_VOLUME_HANDLING, volumeHandling); 10231357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 10241357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 10251357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 10261357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 10271357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * Defines at what volume the playback associated with this route is performed (for user 10281357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * feedback purposes). This information is only used when the playback is not local. 10291357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @param volume 10301357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 10311357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public void setVolume(int volume) { 10328e37a85bf3dc39519942698dc90a3951306b934bAdam Powell volume = Math.max(0, Math.min(volume, getVolumeMax())); 10331357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi if (mVolume != volume) { 10341357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi mVolume = volume; 10351357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi setPlaybackInfoOnRcc(RemoteControlClient.PLAYBACKINFO_VOLUME, volume); 10368e37a85bf3dc39519942698dc90a3951306b934bAdam Powell dispatchRouteVolumeChanged(this); 1037f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell if (mGroup != null) { 1038f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell mGroup.memberVolumeChanged(this); 1039f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell } 10408e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 10418e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 10428e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 10438e37a85bf3dc39519942698dc90a3951306b934bAdam Powell @Override 10448e37a85bf3dc39519942698dc90a3951306b934bAdam Powell public void requestSetVolume(int volume) { 10458e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (mVolumeHandling == PLAYBACK_VOLUME_VARIABLE) { 10468e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (mVcb == null) { 10478e37a85bf3dc39519942698dc90a3951306b934bAdam Powell Log.e(TAG, "Cannot requestSetVolume on user route - no volume callback set"); 10488e37a85bf3dc39519942698dc90a3951306b934bAdam Powell return; 10498e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 10508e37a85bf3dc39519942698dc90a3951306b934bAdam Powell mVcb.vcb.onVolumeSetRequest(this, volume); 10518e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 10528e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 10538e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 10548e37a85bf3dc39519942698dc90a3951306b934bAdam Powell @Override 10558e37a85bf3dc39519942698dc90a3951306b934bAdam Powell public void requestUpdateVolume(int direction) { 10568e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (mVolumeHandling == PLAYBACK_VOLUME_VARIABLE) { 10578e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (mVcb == null) { 10588e37a85bf3dc39519942698dc90a3951306b934bAdam Powell Log.e(TAG, "Cannot requestChangeVolume on user route - no volumec callback set"); 10598e37a85bf3dc39519942698dc90a3951306b934bAdam Powell return; 10608e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 10618e37a85bf3dc39519942698dc90a3951306b934bAdam Powell mVcb.vcb.onVolumeUpdateRequest(this, direction); 10621357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 10631357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 10641357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 10651357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 10661357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * Defines the maximum volume at which the playback associated with this route is performed 10671357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * (for user feedback purposes). This information is only used when the playback is not 10681357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * local. 10691357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @param volumeMax 10701357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 10711357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public void setVolumeMax(int volumeMax) { 10721357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi if (mVolumeMax != volumeMax) { 10731357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi mVolumeMax = volumeMax; 10741357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi setPlaybackInfoOnRcc(RemoteControlClient.PLAYBACKINFO_VOLUME_MAX, volumeMax); 10751357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 10761357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 10771357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 10781357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 10791357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * Defines over what stream type the media is presented. 10801357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @param stream 10811357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 10821357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public void setPlaybackStream(int stream) { 10831357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi if (mPlaybackStream != stream) { 10841357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi mPlaybackStream = stream; 10851357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi setPlaybackInfoOnRcc(RemoteControlClient.PLAYBACKINFO_USES_STREAM, stream); 10861357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 10871357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 10881357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 10891357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi private void updatePlaybackInfoOnRcc() { 10901357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi if ((mRcc != null) && (mRcc.getRcseId() != RemoteControlClient.RCSE_ID_UNREGISTERED)) { 10911357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi mRcc.setPlaybackInformation( 10921357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi RemoteControlClient.PLAYBACKINFO_VOLUME_MAX, mVolumeMax); 10931357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi mRcc.setPlaybackInformation( 10941357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi RemoteControlClient.PLAYBACKINFO_VOLUME, mVolume); 10951357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi mRcc.setPlaybackInformation( 10961357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi RemoteControlClient.PLAYBACKINFO_VOLUME_HANDLING, mVolumeHandling); 10971357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi mRcc.setPlaybackInformation( 10981357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi RemoteControlClient.PLAYBACKINFO_USES_STREAM, mPlaybackStream); 10991357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi mRcc.setPlaybackInformation( 11001357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi RemoteControlClient.PLAYBACKINFO_PLAYBACK_TYPE, mPlaybackType); 11011357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi // let AudioService know whom to call when remote volume needs to be updated 11021357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi try { 11031357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi sStatic.mAudioService.registerRemoteVolumeObserverForRcc( 11041357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi mRcc.getRcseId() /* rccId */, mRemoteVolObserver /* rvo */); 11051357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } catch (RemoteException e) { 11061357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi Log.e(TAG, "Error registering remote volume observer", e); 11071357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 11081357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 11091357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 11101357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 11111357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi private void setPlaybackInfoOnRcc(int what, int value) { 11121357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi if (mRcc != null) { 11131357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi mRcc.setPlaybackInformation(what, value); 11141357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 11151357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 11169a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 11179a1de308cea2d160778fd977825f10a07b49d738Adam Powell 11189a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 11199a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Information about a route that consists of multiple other routes in a group. 11209a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 1121b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn public static class RouteGroup extends RouteInfo { 11229a1de308cea2d160778fd977825f10a07b49d738Adam Powell final ArrayList<RouteInfo> mRoutes = new ArrayList<RouteInfo>(); 11239a1de308cea2d160778fd977825f10a07b49d738Adam Powell private boolean mUpdateName; 11249a1de308cea2d160778fd977825f10a07b49d738Adam Powell 11259a1de308cea2d160778fd977825f10a07b49d738Adam Powell RouteGroup(RouteCategory category) { 11269a1de308cea2d160778fd977825f10a07b49d738Adam Powell super(category); 11279a1de308cea2d160778fd977825f10a07b49d738Adam Powell mGroup = this; 11288e37a85bf3dc39519942698dc90a3951306b934bAdam Powell mVolumeHandling = PLAYBACK_VOLUME_FIXED; 11299a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 11309a1de308cea2d160778fd977825f10a07b49d738Adam Powell 11310d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell CharSequence getName(Resources res) { 11329a1de308cea2d160778fd977825f10a07b49d738Adam Powell if (mUpdateName) updateName(); 11330d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell return super.getName(res); 11349a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 11359a1de308cea2d160778fd977825f10a07b49d738Adam Powell 11369a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 11379a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Add a route to this group. The route must not currently belong to another group. 11389a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 11399a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param route route to add to this group 11409a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 11419a1de308cea2d160778fd977825f10a07b49d738Adam Powell public void addRoute(RouteInfo route) { 11429a1de308cea2d160778fd977825f10a07b49d738Adam Powell if (route.getGroup() != null) { 11439a1de308cea2d160778fd977825f10a07b49d738Adam Powell throw new IllegalStateException("Route " + route + " is already part of a group."); 11449a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 11459a1de308cea2d160778fd977825f10a07b49d738Adam Powell if (route.getCategory() != mCategory) { 11469a1de308cea2d160778fd977825f10a07b49d738Adam Powell throw new IllegalArgumentException( 11479a1de308cea2d160778fd977825f10a07b49d738Adam Powell "Route cannot be added to a group with a different category. " + 11489a1de308cea2d160778fd977825f10a07b49d738Adam Powell "(Route category=" + route.getCategory() + 11499a1de308cea2d160778fd977825f10a07b49d738Adam Powell " group category=" + mCategory + ")"); 11509a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 1151d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell final int at = mRoutes.size(); 11529a1de308cea2d160778fd977825f10a07b49d738Adam Powell mRoutes.add(route); 1153d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell route.mGroup = this; 11549a1de308cea2d160778fd977825f10a07b49d738Adam Powell mUpdateName = true; 1155f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell updateVolume(); 11569a1de308cea2d160778fd977825f10a07b49d738Adam Powell routeUpdated(); 1157f3b653a21cdffe04c94c275e69ecb56e00766e82Adam Powell dispatchRouteGrouped(route, this, at); 11589a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 11599a1de308cea2d160778fd977825f10a07b49d738Adam Powell 11609a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 11619a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Add a route to this group before the specified index. 11629a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 11639a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param route route to add 11649a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param insertAt insert the new route before this index 11659a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 11669a1de308cea2d160778fd977825f10a07b49d738Adam Powell public void addRoute(RouteInfo route, int insertAt) { 11679a1de308cea2d160778fd977825f10a07b49d738Adam Powell if (route.getGroup() != null) { 11689a1de308cea2d160778fd977825f10a07b49d738Adam Powell throw new IllegalStateException("Route " + route + " is already part of a group."); 11699a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 11709a1de308cea2d160778fd977825f10a07b49d738Adam Powell if (route.getCategory() != mCategory) { 11719a1de308cea2d160778fd977825f10a07b49d738Adam Powell throw new IllegalArgumentException( 11729a1de308cea2d160778fd977825f10a07b49d738Adam Powell "Route cannot be added to a group with a different category. " + 11739a1de308cea2d160778fd977825f10a07b49d738Adam Powell "(Route category=" + route.getCategory() + 11749a1de308cea2d160778fd977825f10a07b49d738Adam Powell " group category=" + mCategory + ")"); 11759a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 11769a1de308cea2d160778fd977825f10a07b49d738Adam Powell mRoutes.add(insertAt, route); 1177d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell route.mGroup = this; 11789a1de308cea2d160778fd977825f10a07b49d738Adam Powell mUpdateName = true; 1179f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell updateVolume(); 11809a1de308cea2d160778fd977825f10a07b49d738Adam Powell routeUpdated(); 1181f3b653a21cdffe04c94c275e69ecb56e00766e82Adam Powell dispatchRouteGrouped(route, this, insertAt); 11829a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 11839a1de308cea2d160778fd977825f10a07b49d738Adam Powell 11849a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 11859a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Remove a route from this group. 11869a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 11879a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param route route to remove 11889a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 11899a1de308cea2d160778fd977825f10a07b49d738Adam Powell public void removeRoute(RouteInfo route) { 11909a1de308cea2d160778fd977825f10a07b49d738Adam Powell if (route.getGroup() != this) { 11919a1de308cea2d160778fd977825f10a07b49d738Adam Powell throw new IllegalArgumentException("Route " + route + 11929a1de308cea2d160778fd977825f10a07b49d738Adam Powell " is not a member of this group."); 11939a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 11949a1de308cea2d160778fd977825f10a07b49d738Adam Powell mRoutes.remove(route); 1195d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell route.mGroup = null; 11969a1de308cea2d160778fd977825f10a07b49d738Adam Powell mUpdateName = true; 1197f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell updateVolume(); 1198d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell dispatchRouteUngrouped(route, this); 11999a1de308cea2d160778fd977825f10a07b49d738Adam Powell routeUpdated(); 12009a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 12019a1de308cea2d160778fd977825f10a07b49d738Adam Powell 12029a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 12039a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Remove the route at the specified index from this group. 12049a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 12059a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param index index of the route to remove 12069a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 12079a1de308cea2d160778fd977825f10a07b49d738Adam Powell public void removeRoute(int index) { 1208d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell RouteInfo route = mRoutes.remove(index); 1209d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell route.mGroup = null; 12109a1de308cea2d160778fd977825f10a07b49d738Adam Powell mUpdateName = true; 1211f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell updateVolume(); 1212d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell dispatchRouteUngrouped(route, this); 12139a1de308cea2d160778fd977825f10a07b49d738Adam Powell routeUpdated(); 12149a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 12159a1de308cea2d160778fd977825f10a07b49d738Adam Powell 1216d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell /** 1217d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @return The number of routes in this group 1218d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell */ 1219d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell public int getRouteCount() { 1220d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell return mRoutes.size(); 1221d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell } 1222d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell 1223d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell /** 1224d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * Return the route in this group at the specified index 1225d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * 1226d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param index Index to fetch 1227d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @return The route at index 1228d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell */ 1229d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell public RouteInfo getRouteAt(int index) { 1230d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell return mRoutes.get(index); 1231d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell } 1232d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell 1233ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell /** 1234ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * Set an icon that will be used to represent this group. 1235ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * The system may use this icon in picker UIs or similar. 1236ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * 1237ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * @param icon icon drawable to use to represent this group 1238ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell */ 1239ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell public void setIconDrawable(Drawable icon) { 1240ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell mIcon = icon; 1241ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell } 1242ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell 1243ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell /** 1244ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * Set an icon that will be used to represent this group. 1245ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * The system may use this icon in picker UIs or similar. 1246ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * 124771c69897ad0a55d590698bfa399bfe99c763b9dbAdam Powell * @param resId Resource ID of an icon drawable to use to represent this group 1248ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell */ 1249ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell public void setIconResource(int resId) { 1250ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell setIconDrawable(sStatic.mResources.getDrawable(resId)); 1251ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell } 1252ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell 12538e37a85bf3dc39519942698dc90a3951306b934bAdam Powell @Override 12548e37a85bf3dc39519942698dc90a3951306b934bAdam Powell public void requestSetVolume(int volume) { 12558e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final int maxVol = getVolumeMax(); 12568e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (maxVol == 0) { 12578e37a85bf3dc39519942698dc90a3951306b934bAdam Powell return; 12588e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 12598e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 12608e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final float scaledVolume = (float) volume / maxVol; 12618e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final int routeCount = getRouteCount(); 12628e37a85bf3dc39519942698dc90a3951306b934bAdam Powell for (int i = 0; i < routeCount; i++) { 12638e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final RouteInfo route = getRouteAt(i); 12648e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final int routeVol = (int) (scaledVolume * route.getVolumeMax()); 12658e37a85bf3dc39519942698dc90a3951306b934bAdam Powell route.requestSetVolume(routeVol); 12668e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 12678e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (volume != mVolume) { 12688e37a85bf3dc39519942698dc90a3951306b934bAdam Powell mVolume = volume; 12698e37a85bf3dc39519942698dc90a3951306b934bAdam Powell dispatchRouteVolumeChanged(this); 12708e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 12718e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 12728e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 12738e37a85bf3dc39519942698dc90a3951306b934bAdam Powell @Override 12748e37a85bf3dc39519942698dc90a3951306b934bAdam Powell public void requestUpdateVolume(int direction) { 12758e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final int maxVol = getVolumeMax(); 12768e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (maxVol == 0) { 12778e37a85bf3dc39519942698dc90a3951306b934bAdam Powell return; 12788e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 12798e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 12808e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final int routeCount = getRouteCount(); 1281f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell int volume = 0; 12828e37a85bf3dc39519942698dc90a3951306b934bAdam Powell for (int i = 0; i < routeCount; i++) { 12838e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final RouteInfo route = getRouteAt(i); 12848e37a85bf3dc39519942698dc90a3951306b934bAdam Powell route.requestUpdateVolume(direction); 1285f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell final int routeVol = route.getVolume(); 1286f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell if (routeVol > volume) { 1287f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell volume = routeVol; 1288f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell } 12898e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 12908e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (volume != mVolume) { 12918e37a85bf3dc39519942698dc90a3951306b934bAdam Powell mVolume = volume; 12928e37a85bf3dc39519942698dc90a3951306b934bAdam Powell dispatchRouteVolumeChanged(this); 12938e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 12948e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 12958e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 12969a1de308cea2d160778fd977825f10a07b49d738Adam Powell void memberNameChanged(RouteInfo info, CharSequence name) { 12979a1de308cea2d160778fd977825f10a07b49d738Adam Powell mUpdateName = true; 12989a1de308cea2d160778fd977825f10a07b49d738Adam Powell routeUpdated(); 12999a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 13009a1de308cea2d160778fd977825f10a07b49d738Adam Powell 13019a1de308cea2d160778fd977825f10a07b49d738Adam Powell void memberStatusChanged(RouteInfo info, CharSequence status) { 13029a1de308cea2d160778fd977825f10a07b49d738Adam Powell setStatusInt(status); 13039a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 13049a1de308cea2d160778fd977825f10a07b49d738Adam Powell 1305f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell void memberVolumeChanged(RouteInfo info) { 1306f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell updateVolume(); 1307f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell } 1308f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell 1309f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell void updateVolume() { 1310f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell // A group always represents the highest component volume value. 1311f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell final int routeCount = getRouteCount(); 1312f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell int volume = 0; 1313f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell for (int i = 0; i < routeCount; i++) { 1314f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell final int routeVol = getRouteAt(i).getVolume(); 1315f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell if (routeVol > volume) { 1316f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell volume = routeVol; 1317f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell } 1318f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell } 1319f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell if (volume != mVolume) { 1320f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell mVolume = volume; 1321f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell dispatchRouteVolumeChanged(this); 1322f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell } 1323f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell } 1324f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell 1325d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell @Override 1326d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell void routeUpdated() { 1327d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell int types = 0; 1328d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell final int count = mRoutes.size(); 1329b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell if (count == 0) { 1330b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell // Don't keep empty groups in the router. 1331b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell MediaRouter.removeRoute(this); 1332b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell return; 1333b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell } 1334b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell 13358e37a85bf3dc39519942698dc90a3951306b934bAdam Powell int maxVolume = 0; 13368e37a85bf3dc39519942698dc90a3951306b934bAdam Powell boolean isLocal = true; 13378e37a85bf3dc39519942698dc90a3951306b934bAdam Powell boolean isFixedVolume = true; 1338d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell for (int i = 0; i < count; i++) { 13398e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final RouteInfo route = mRoutes.get(i); 13408e37a85bf3dc39519942698dc90a3951306b934bAdam Powell types |= route.mSupportedTypes; 13418e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final int routeMaxVolume = route.getVolumeMax(); 13428e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (routeMaxVolume > maxVolume) { 13438e37a85bf3dc39519942698dc90a3951306b934bAdam Powell maxVolume = routeMaxVolume; 13448e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 13458e37a85bf3dc39519942698dc90a3951306b934bAdam Powell isLocal &= route.getPlaybackType() == PLAYBACK_TYPE_LOCAL; 13468e37a85bf3dc39519942698dc90a3951306b934bAdam Powell isFixedVolume &= route.getVolumeHandling() == PLAYBACK_VOLUME_FIXED; 1347d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell } 13488e37a85bf3dc39519942698dc90a3951306b934bAdam Powell mPlaybackType = isLocal ? PLAYBACK_TYPE_LOCAL : PLAYBACK_TYPE_REMOTE; 13498e37a85bf3dc39519942698dc90a3951306b934bAdam Powell mVolumeHandling = isFixedVolume ? PLAYBACK_VOLUME_FIXED : PLAYBACK_VOLUME_VARIABLE; 1350d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell mSupportedTypes = types; 13518e37a85bf3dc39519942698dc90a3951306b934bAdam Powell mVolumeMax = maxVolume; 1352d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell mIcon = count == 1 ? mRoutes.get(0).getIconDrawable() : null; 1353d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell super.routeUpdated(); 1354d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell } 1355d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell 13569a1de308cea2d160778fd977825f10a07b49d738Adam Powell void updateName() { 13579a1de308cea2d160778fd977825f10a07b49d738Adam Powell final StringBuilder sb = new StringBuilder(); 13589a1de308cea2d160778fd977825f10a07b49d738Adam Powell final int count = mRoutes.size(); 13599a1de308cea2d160778fd977825f10a07b49d738Adam Powell for (int i = 0; i < count; i++) { 13609a1de308cea2d160778fd977825f10a07b49d738Adam Powell final RouteInfo info = mRoutes.get(i); 1361b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell // TODO: There's probably a much more correct way to localize this. 13629a1de308cea2d160778fd977825f10a07b49d738Adam Powell if (i > 0) sb.append(", "); 13639a1de308cea2d160778fd977825f10a07b49d738Adam Powell sb.append(info.mName); 13649a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 13659a1de308cea2d160778fd977825f10a07b49d738Adam Powell mName = sb.toString(); 13669a1de308cea2d160778fd977825f10a07b49d738Adam Powell mUpdateName = false; 13679a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 1368d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell 1369d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell @Override 1370d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell public String toString() { 1371d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell StringBuilder sb = new StringBuilder(super.toString()); 1372d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell sb.append('['); 1373d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell final int count = mRoutes.size(); 1374d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell for (int i = 0; i < count; i++) { 1375d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell if (i > 0) sb.append(", "); 1376d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell sb.append(mRoutes.get(i)); 1377d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell } 1378d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell sb.append(']'); 1379d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell return sb.toString(); 1380d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell } 13819a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 13829a1de308cea2d160778fd977825f10a07b49d738Adam Powell 13839a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 13849a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Definition of a category of routes. All routes belong to a category. 13859a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 1386b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn public static class RouteCategory { 13879a1de308cea2d160778fd977825f10a07b49d738Adam Powell CharSequence mName; 13880d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell int mNameResId; 13899a1de308cea2d160778fd977825f10a07b49d738Adam Powell int mTypes; 13909a1de308cea2d160778fd977825f10a07b49d738Adam Powell final boolean mGroupable; 13919a1de308cea2d160778fd977825f10a07b49d738Adam Powell 13929a1de308cea2d160778fd977825f10a07b49d738Adam Powell RouteCategory(CharSequence name, int types, boolean groupable) { 13939a1de308cea2d160778fd977825f10a07b49d738Adam Powell mName = name; 13949a1de308cea2d160778fd977825f10a07b49d738Adam Powell mTypes = types; 13959a1de308cea2d160778fd977825f10a07b49d738Adam Powell mGroupable = groupable; 13969a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 13979a1de308cea2d160778fd977825f10a07b49d738Adam Powell 13980d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell RouteCategory(int nameResId, int types, boolean groupable) { 13990d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell mNameResId = nameResId; 14000d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell mTypes = types; 14010d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell mGroupable = groupable; 14020d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell } 14030d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell 14049a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 14059a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @return the name of this route category 14069a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 14079a1de308cea2d160778fd977825f10a07b49d738Adam Powell public CharSequence getName() { 14080d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell return getName(sStatic.mResources); 14090d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell } 14100d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell 14110d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell /** 14120d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * Return the properly localized/configuration dependent name of this RouteCategory. 14130d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * 14140d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * @param context Context to resolve name resources 14150d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * @return the name of this route category 14160d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell */ 14170d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public CharSequence getName(Context context) { 14180d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell return getName(context.getResources()); 14190d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell } 14200d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell 14210d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell CharSequence getName(Resources res) { 14220d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell if (mNameResId != 0) { 14230d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell return res.getText(mNameResId); 14240d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell } 14259a1de308cea2d160778fd977825f10a07b49d738Adam Powell return mName; 14269a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 14279a1de308cea2d160778fd977825f10a07b49d738Adam Powell 14289a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 1429d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * Return the current list of routes in this category that have been added 1430d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * to the MediaRouter. 14319a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 1432d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * <p>This list will not include routes that are nested within RouteGroups. 1433d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * A RouteGroup is treated as a single route within its category.</p> 1434d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * 1435d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param out a List to fill with the routes in this category. If this parameter is 1436d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * non-null, it will be cleared, filled with the current routes with this 1437d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * category, and returned. If this parameter is null, a new List will be 1438d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * allocated to report the category's current routes. 1439d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @return A list with the routes in this category that have been added to the MediaRouter. 14409a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 1441d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell public List<RouteInfo> getRoutes(List<RouteInfo> out) { 1442d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell if (out == null) { 1443d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell out = new ArrayList<RouteInfo>(); 1444d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell } else { 1445d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell out.clear(); 1446d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell } 1447d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell 1448b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn final int count = getRouteCountStatic(); 1449d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell for (int i = 0; i < count; i++) { 1450b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn final RouteInfo route = getRouteAtStatic(i); 1451d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell if (route.mCategory == this) { 1452d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell out.add(route); 1453d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell } 1454d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell } 1455d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell return out; 14569a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 14579a1de308cea2d160778fd977825f10a07b49d738Adam Powell 14589a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 14599a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @return Flag set describing the route types supported by this category 14609a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 14619a1de308cea2d160778fd977825f10a07b49d738Adam Powell public int getSupportedTypes() { 14629a1de308cea2d160778fd977825f10a07b49d738Adam Powell return mTypes; 14639a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 14649a1de308cea2d160778fd977825f10a07b49d738Adam Powell 14659a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 14669a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Return whether or not this category supports grouping. 14679a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 14689a1de308cea2d160778fd977825f10a07b49d738Adam Powell * <p>If this method returns true, all routes obtained from this category 1469d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * via calls to {@link #getRouteAt(int)} will be {@link MediaRouter.RouteGroup}s.</p> 14709a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 14719a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @return true if this category supports 14729a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 14739a1de308cea2d160778fd977825f10a07b49d738Adam Powell public boolean isGroupable() { 14749a1de308cea2d160778fd977825f10a07b49d738Adam Powell return mGroupable; 14759a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 14769a1de308cea2d160778fd977825f10a07b49d738Adam Powell 14779a1de308cea2d160778fd977825f10a07b49d738Adam Powell public String toString() { 14789a1de308cea2d160778fd977825f10a07b49d738Adam Powell return "RouteCategory{ name=" + mName + " types=" + typesToString(mTypes) + 1479d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell " groupable=" + mGroupable + " }"; 14809a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 14819a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 14829a1de308cea2d160778fd977825f10a07b49d738Adam Powell 14839a1de308cea2d160778fd977825f10a07b49d738Adam Powell static class CallbackInfo { 14849a1de308cea2d160778fd977825f10a07b49d738Adam Powell public int type; 1485b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn public final Callback cb; 1486b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn public final MediaRouter router; 14879a1de308cea2d160778fd977825f10a07b49d738Adam Powell 1488b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn public CallbackInfo(Callback cb, int type, MediaRouter router) { 14899a1de308cea2d160778fd977825f10a07b49d738Adam Powell this.cb = cb; 14909a1de308cea2d160778fd977825f10a07b49d738Adam Powell this.type = type; 1491b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn this.router = router; 14929a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 14939a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 14949a1de308cea2d160778fd977825f10a07b49d738Adam Powell 14959a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 14969a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Interface for receiving events about media routing changes. 14979a1de308cea2d160778fd977825f10a07b49d738Adam Powell * All methods of this interface will be called from the application's main thread. 14989a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 14999a1de308cea2d160778fd977825f10a07b49d738Adam Powell * <p>A Callback will only receive events relevant to routes that the callback 15009a1de308cea2d160778fd977825f10a07b49d738Adam Powell * was registered for.</p> 15019a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 15029a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @see MediaRouter#addCallback(int, Callback) 15039a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @see MediaRouter#removeCallback(Callback) 15049a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 15050d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public static abstract class Callback { 15069a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 15079a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Called when the supplied route becomes selected as the active route 15089a1de308cea2d160778fd977825f10a07b49d738Adam Powell * for the given route type. 15099a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 1510d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param router the MediaRouter reporting the event 15119a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param type Type flag set indicating the routes that have been selected 15129a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param info Route that has been selected for the given route types 15139a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 15140d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public abstract void onRouteSelected(MediaRouter router, int type, RouteInfo info); 15159a1de308cea2d160778fd977825f10a07b49d738Adam Powell 15169a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 15179a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Called when the supplied route becomes unselected as the active route 15189a1de308cea2d160778fd977825f10a07b49d738Adam Powell * for the given route type. 15199a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 1520d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param router the MediaRouter reporting the event 15219a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param type Type flag set indicating the routes that have been unselected 15229a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param info Route that has been unselected for the given route types 15239a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 15240d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public abstract void onRouteUnselected(MediaRouter router, int type, RouteInfo info); 15259a1de308cea2d160778fd977825f10a07b49d738Adam Powell 15269a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 15279a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Called when a route for the specified type was added. 15289a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 1529d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param router the MediaRouter reporting the event 15309a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param info Route that has become available for use 15319a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 15320d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public abstract void onRouteAdded(MediaRouter router, RouteInfo info); 15339a1de308cea2d160778fd977825f10a07b49d738Adam Powell 15349a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 15359a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Called when a route for the specified type was removed. 15369a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 1537d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param router the MediaRouter reporting the event 15389a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param info Route that has been removed from availability 15399a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 15400d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public abstract void onRouteRemoved(MediaRouter router, RouteInfo info); 15419a1de308cea2d160778fd977825f10a07b49d738Adam Powell 15429a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 15439a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Called when an aspect of the indicated route has changed. 15449a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 15459a1de308cea2d160778fd977825f10a07b49d738Adam Powell * <p>This will not indicate that the types supported by this route have 15469a1de308cea2d160778fd977825f10a07b49d738Adam Powell * changed, only that cosmetic info such as name or status have been updated.</p> 15479a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 1548d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param router the MediaRouter reporting the event 15499a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param info The route that was changed 15509a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 15510d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public abstract void onRouteChanged(MediaRouter router, RouteInfo info); 1552d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell 1553d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell /** 1554d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * Called when a route is added to a group. 1555d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * 1556d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param router the MediaRouter reporting the event 1557d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param info The route that was added 1558d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param group The group the route was added to 1559d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param index The route index within group that info was added at 1560d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell */ 15610d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public abstract void onRouteGrouped(MediaRouter router, RouteInfo info, RouteGroup group, 15620d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell int index); 1563d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell 1564d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell /** 1565d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * Called when a route is removed from a group. 1566d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * 1567d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param router the MediaRouter reporting the event 1568d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param info The route that was removed 1569d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param group The group the route was removed from 1570d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell */ 15710d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public abstract void onRouteUngrouped(MediaRouter router, RouteInfo info, RouteGroup group); 15728e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 15738e37a85bf3dc39519942698dc90a3951306b934bAdam Powell /** 15748e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * Called when a route's volume changes. 15758e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * 15768e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * @param router the MediaRouter reporting the event 15778e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * @param info The route with altered volume 15788e37a85bf3dc39519942698dc90a3951306b934bAdam Powell */ 15798e37a85bf3dc39519942698dc90a3951306b934bAdam Powell public abstract void onRouteVolumeChanged(MediaRouter router, RouteInfo info); 15809a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 15819a1de308cea2d160778fd977825f10a07b49d738Adam Powell 15829a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 15830d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * Stub implementation of {@link MediaRouter.Callback}. 15840d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * Each abstract method is defined as a no-op. Override just the ones 15859a1de308cea2d160778fd977825f10a07b49d738Adam Powell * you need. 15869a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 15870d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public static class SimpleCallback extends Callback { 15889a1de308cea2d160778fd977825f10a07b49d738Adam Powell 15899a1de308cea2d160778fd977825f10a07b49d738Adam Powell @Override 1590d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell public void onRouteSelected(MediaRouter router, int type, RouteInfo info) { 15919a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 15929a1de308cea2d160778fd977825f10a07b49d738Adam Powell 15939a1de308cea2d160778fd977825f10a07b49d738Adam Powell @Override 1594d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell public void onRouteUnselected(MediaRouter router, int type, RouteInfo info) { 15959a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 15969a1de308cea2d160778fd977825f10a07b49d738Adam Powell 15979a1de308cea2d160778fd977825f10a07b49d738Adam Powell @Override 1598d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell public void onRouteAdded(MediaRouter router, RouteInfo info) { 15999a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 16009a1de308cea2d160778fd977825f10a07b49d738Adam Powell 16019a1de308cea2d160778fd977825f10a07b49d738Adam Powell @Override 1602d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell public void onRouteRemoved(MediaRouter router, RouteInfo info) { 16039a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 16049a1de308cea2d160778fd977825f10a07b49d738Adam Powell 16059a1de308cea2d160778fd977825f10a07b49d738Adam Powell @Override 1606d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell public void onRouteChanged(MediaRouter router, RouteInfo info) { 16079a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 16089a1de308cea2d160778fd977825f10a07b49d738Adam Powell 16099a1de308cea2d160778fd977825f10a07b49d738Adam Powell @Override 1610d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell public void onRouteGrouped(MediaRouter router, RouteInfo info, RouteGroup group, 1611d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell int index) { 16129a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 16139a1de308cea2d160778fd977825f10a07b49d738Adam Powell 16149a1de308cea2d160778fd977825f10a07b49d738Adam Powell @Override 1615d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell public void onRouteUngrouped(MediaRouter router, RouteInfo info, RouteGroup group) { 16169a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 1617d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell 16188e37a85bf3dc39519942698dc90a3951306b934bAdam Powell @Override 16198e37a85bf3dc39519942698dc90a3951306b934bAdam Powell public void onRouteVolumeChanged(MediaRouter router, RouteInfo info) { 16208e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 16219a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 16221357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 16231357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi static class VolumeCallbackInfo { 16241357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public final VolumeCallback vcb; 16251357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public final RouteInfo route; 16261357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 16271357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public VolumeCallbackInfo(VolumeCallback vcb, RouteInfo route) { 16281357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi this.vcb = vcb; 16291357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi this.route = route; 16301357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 16311357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 16321357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 16331357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 16341357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * Interface for receiving events about volume changes. 16351357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * All methods of this interface will be called from the application's main thread. 16361357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * 16371357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * <p>A VolumeCallback will only receive events relevant to routes that the callback 16381357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * was registered for.</p> 16391357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * 16401357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @see UserRouteInfo#setVolumeCallback(VolumeCallback) 16411357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 16421357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public static abstract class VolumeCallback { 16431357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 16441357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * Called when the volume for the route should be increased or decreased. 16451357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @param info the route affected by this event 16461357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @param direction an integer indicating whether the volume is to be increased 16471357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * (positive value) or decreased (negative value). 16481357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * For bundled changes, the absolute value indicates the number of changes 16491357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * in the same direction, e.g. +3 corresponds to three "volume up" changes. 16501357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 16511357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public abstract void onVolumeUpdateRequest(RouteInfo info, int direction); 16521357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 16531357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * Called when the volume for the route should be set to the given value 16541357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @param info the route affected by this event 16551357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @param volume an integer indicating the new volume value that should be used, always 16561357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * between 0 and the value set by {@link UserRouteInfo#setVolumeMax(int)}. 16571357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 16581357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public abstract void onVolumeSetRequest(RouteInfo info, int volume); 16591357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 16601357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 16618e37a85bf3dc39519942698dc90a3951306b934bAdam Powell static class VolumeChangeReceiver extends BroadcastReceiver { 16628e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 16638e37a85bf3dc39519942698dc90a3951306b934bAdam Powell @Override 16648e37a85bf3dc39519942698dc90a3951306b934bAdam Powell public void onReceive(Context context, Intent intent) { 16658e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (intent.getAction().equals(AudioManager.VOLUME_CHANGED_ACTION)) { 16668e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final int streamType = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, 16678e37a85bf3dc39519942698dc90a3951306b934bAdam Powell -1); 16688e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (streamType != AudioManager.STREAM_MUSIC) { 16698e37a85bf3dc39519942698dc90a3951306b934bAdam Powell return; 16708e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 16718e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 16728e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final int newVolume = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, 0); 16738e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final int oldVolume = intent.getIntExtra( 16748e37a85bf3dc39519942698dc90a3951306b934bAdam Powell AudioManager.EXTRA_PREV_VOLUME_STREAM_VALUE, 0); 16758e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (newVolume != oldVolume) { 16768e37a85bf3dc39519942698dc90a3951306b934bAdam Powell systemVolumeChanged(newVolume); 16778e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 16788e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 16798e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 16808e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 16818e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 16829a1de308cea2d160778fd977825f10a07b49d738Adam Powell} 1683