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 } 129bcf21e913af7252fb1994e07b6cf179321ecd049Adam Powell 130bcf21e913af7252fb1994e07b6cf179321ecd049Adam Powell boolean a2dpEnabled; 131bcf21e913af7252fb1994e07b6cf179321ecd049Adam Powell try { 132bcf21e913af7252fb1994e07b6cf179321ecd049Adam Powell a2dpEnabled = mAudioService.isBluetoothA2dpOn(); 133bcf21e913af7252fb1994e07b6cf179321ecd049Adam Powell } catch (RemoteException e) { 134bcf21e913af7252fb1994e07b6cf179321ecd049Adam Powell Log.e(TAG, "Error querying Bluetooth A2DP state", e); 135bcf21e913af7252fb1994e07b6cf179321ecd049Adam Powell a2dpEnabled = false; 136bcf21e913af7252fb1994e07b6cf179321ecd049Adam Powell } 137bcf21e913af7252fb1994e07b6cf179321ecd049Adam Powell 138632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn if (!TextUtils.equals(newRoutes.mBluetoothName, mCurRoutesInfo.mBluetoothName)) { 139632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn mCurRoutesInfo.mBluetoothName = newRoutes.mBluetoothName; 140632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn if (mCurRoutesInfo.mBluetoothName != null) { 141632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn if (sStatic.mBluetoothA2dpRoute == null) { 142632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn final RouteInfo info = new RouteInfo(sStatic.mSystemCategory); 143632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn info.mName = mCurRoutesInfo.mBluetoothName; 144632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn info.mSupportedTypes = ROUTE_TYPE_LIVE_AUDIO; 145632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn sStatic.mBluetoothA2dpRoute = info; 146632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn addRoute(sStatic.mBluetoothA2dpRoute); 147632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } else { 148632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn sStatic.mBluetoothA2dpRoute.mName = mCurRoutesInfo.mBluetoothName; 149632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn dispatchRouteChanged(sStatic.mBluetoothA2dpRoute); 150632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } 151632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } else if (sStatic.mBluetoothA2dpRoute != null) { 152632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn removeRoute(sStatic.mBluetoothA2dpRoute); 153632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn sStatic.mBluetoothA2dpRoute = null; 154632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } 155632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } 156bcf21e913af7252fb1994e07b6cf179321ecd049Adam Powell 157bcf21e913af7252fb1994e07b6cf179321ecd049Adam Powell if (mBluetoothA2dpRoute != null) { 158bcf21e913af7252fb1994e07b6cf179321ecd049Adam Powell if (mCurRoutesInfo.mMainType != AudioRoutesInfo.MAIN_SPEAKER && 159bcf21e913af7252fb1994e07b6cf179321ecd049Adam Powell mSelectedRoute == mBluetoothA2dpRoute) { 160bcf21e913af7252fb1994e07b6cf179321ecd049Adam Powell selectRouteStatic(ROUTE_TYPE_LIVE_AUDIO, mDefaultAudio); 161bcf21e913af7252fb1994e07b6cf179321ecd049Adam Powell } else if (mCurRoutesInfo.mMainType == AudioRoutesInfo.MAIN_SPEAKER && 162bcf21e913af7252fb1994e07b6cf179321ecd049Adam Powell mSelectedRoute == mDefaultAudio && a2dpEnabled) { 163bcf21e913af7252fb1994e07b6cf179321ecd049Adam Powell selectRouteStatic(ROUTE_TYPE_LIVE_AUDIO, mBluetoothA2dpRoute); 164bcf21e913af7252fb1994e07b6cf179321ecd049Adam Powell } 165bcf21e913af7252fb1994e07b6cf179321ecd049Adam Powell } 166b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn } 167b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn } 1689a1de308cea2d160778fd977825f10a07b49d738Adam Powell 169b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn static Static sStatic; 1709a1de308cea2d160778fd977825f10a07b49d738Adam Powell 1719a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 1729a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Route type flag for live audio. 1739a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 1749a1de308cea2d160778fd977825f10a07b49d738Adam Powell * <p>A device that supports live audio routing will allow the media audio stream 1759a1de308cea2d160778fd977825f10a07b49d738Adam Powell * to be routed to supported destinations. This can include internal speakers or 1769a1de308cea2d160778fd977825f10a07b49d738Adam Powell * audio jacks on the device itself, A2DP devices, and more.</p> 1779a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 1789a1de308cea2d160778fd977825f10a07b49d738Adam Powell * <p>Once initiated this routing is transparent to the application. All audio 1799a1de308cea2d160778fd977825f10a07b49d738Adam Powell * played on the media stream will be routed to the selected destination.</p> 1809a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 1819a1de308cea2d160778fd977825f10a07b49d738Adam Powell public static final int ROUTE_TYPE_LIVE_AUDIO = 0x1; 1829a1de308cea2d160778fd977825f10a07b49d738Adam Powell 1839a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 1849a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Route type flag for application-specific usage. 1859a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 1869a1de308cea2d160778fd977825f10a07b49d738Adam Powell * <p>Unlike other media route types, user routes are managed by the application. 1879a1de308cea2d160778fd977825f10a07b49d738Adam Powell * The MediaRouter will manage and dispatch events for user routes, but the application 1889a1de308cea2d160778fd977825f10a07b49d738Adam Powell * is expected to interpret the meaning of these events and perform the requested 1899a1de308cea2d160778fd977825f10a07b49d738Adam Powell * routing tasks.</p> 1909a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 1919a1de308cea2d160778fd977825f10a07b49d738Adam Powell public static final int ROUTE_TYPE_USER = 0x00800000; 1929a1de308cea2d160778fd977825f10a07b49d738Adam Powell 1939a1de308cea2d160778fd977825f10a07b49d738Adam Powell // Maps application contexts 1949a1de308cea2d160778fd977825f10a07b49d738Adam Powell static final HashMap<Context, MediaRouter> sRouters = new HashMap<Context, MediaRouter>(); 1959a1de308cea2d160778fd977825f10a07b49d738Adam Powell 1969a1de308cea2d160778fd977825f10a07b49d738Adam Powell static String typesToString(int types) { 1979a1de308cea2d160778fd977825f10a07b49d738Adam Powell final StringBuilder result = new StringBuilder(); 1989a1de308cea2d160778fd977825f10a07b49d738Adam Powell if ((types & ROUTE_TYPE_LIVE_AUDIO) != 0) { 1999a1de308cea2d160778fd977825f10a07b49d738Adam Powell result.append("ROUTE_TYPE_LIVE_AUDIO "); 2009a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 2019a1de308cea2d160778fd977825f10a07b49d738Adam Powell if ((types & ROUTE_TYPE_USER) != 0) { 2029a1de308cea2d160778fd977825f10a07b49d738Adam Powell result.append("ROUTE_TYPE_USER "); 2039a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 2049a1de308cea2d160778fd977825f10a07b49d738Adam Powell return result.toString(); 2059a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 2069a1de308cea2d160778fd977825f10a07b49d738Adam Powell 207b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn /** @hide */ 208b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn public MediaRouter(Context context) { 209b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn synchronized (Static.class) { 210b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn if (sStatic == null) { 2118e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final Context appContext = context.getApplicationContext(); 2128e37a85bf3dc39519942698dc90a3951306b934bAdam Powell sStatic = new Static(appContext); 2138e37a85bf3dc39519942698dc90a3951306b934bAdam Powell sStatic.startMonitoringRoutes(appContext); 214b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn } 2159a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 2169a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 2179a1de308cea2d160778fd977825f10a07b49d738Adam Powell 218690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell /** 219690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell * @hide for use by framework routing UI 220690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell */ 221690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell public RouteInfo getSystemAudioRoute() { 222b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn return sStatic.mDefaultAudio; 223690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell } 224690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell 225690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell /** 2264599696591f745b3a546197d2ba7e5cfc5562484Adam Powell * @hide for use by framework routing UI 2274599696591f745b3a546197d2ba7e5cfc5562484Adam Powell */ 2284599696591f745b3a546197d2ba7e5cfc5562484Adam Powell public RouteCategory getSystemAudioCategory() { 2294599696591f745b3a546197d2ba7e5cfc5562484Adam Powell return sStatic.mSystemCategory; 2304599696591f745b3a546197d2ba7e5cfc5562484Adam Powell } 2314599696591f745b3a546197d2ba7e5cfc5562484Adam Powell 2324599696591f745b3a546197d2ba7e5cfc5562484Adam Powell /** 233690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell * Return the currently selected route for the given types 234690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell * 235690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell * @param type route types 236690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell * @return the selected route 237690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell */ 238690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell public RouteInfo getSelectedRoute(int type) { 239b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn return sStatic.mSelectedRoute; 240690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell } 241690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell 2429a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 2439a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Add a callback to listen to events about specific kinds of media routes. 2449a1de308cea2d160778fd977825f10a07b49d738Adam Powell * If the specified callback is already registered, its registration will be updated for any 2459a1de308cea2d160778fd977825f10a07b49d738Adam Powell * additional route types specified. 2469a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 2479a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param types Types of routes this callback is interested in 2489a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param cb Callback to add 2499a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 2509a1de308cea2d160778fd977825f10a07b49d738Adam Powell public void addCallback(int types, Callback cb) { 251b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn final int count = sStatic.mCallbacks.size(); 2529a1de308cea2d160778fd977825f10a07b49d738Adam Powell for (int i = 0; i < count; i++) { 253b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn final CallbackInfo info = sStatic.mCallbacks.get(i); 2549a1de308cea2d160778fd977825f10a07b49d738Adam Powell if (info.cb == cb) { 255dbbfa702a09f6d2d36dee1b552442d04a4673f89Adam Powell info.type |= types; 2569a1de308cea2d160778fd977825f10a07b49d738Adam Powell return; 2579a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 2589a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 259b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn sStatic.mCallbacks.add(new CallbackInfo(cb, types, this)); 2609a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 2619a1de308cea2d160778fd977825f10a07b49d738Adam Powell 2629a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 2639a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Remove the specified callback. It will no longer receive events about media routing. 2649a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 2659a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param cb Callback to remove 2669a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 2679a1de308cea2d160778fd977825f10a07b49d738Adam Powell public void removeCallback(Callback cb) { 268b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn final int count = sStatic.mCallbacks.size(); 2699a1de308cea2d160778fd977825f10a07b49d738Adam Powell for (int i = 0; i < count; i++) { 270b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn if (sStatic.mCallbacks.get(i).cb == cb) { 271b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn sStatic.mCallbacks.remove(i); 2729a1de308cea2d160778fd977825f10a07b49d738Adam Powell return; 2739a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 2749a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 2759a1de308cea2d160778fd977825f10a07b49d738Adam Powell Log.w(TAG, "removeCallback(" + cb + "): callback not registered"); 2769a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 2779a1de308cea2d160778fd977825f10a07b49d738Adam Powell 278d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell /** 279d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * Select the specified route to use for output of the given media types. 280d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * 281d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param types type flags indicating which types this route should be used for. 282d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * The route must support at least a subset. 283d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param route Route to select 284d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell */ 2859a1de308cea2d160778fd977825f10a07b49d738Adam Powell public void selectRoute(int types, RouteInfo route) { 2860d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell // Applications shouldn't programmatically change anything but user routes. 2870d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell types &= ROUTE_TYPE_USER; 2880d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell selectRouteStatic(types, route); 2890d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell } 2900d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell 2910d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell /** 2920d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * @hide internal use 2930d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell */ 2940d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public void selectRouteInt(int types, RouteInfo route) { 295b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn selectRouteStatic(types, route); 296b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn } 297b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn 298b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn static void selectRouteStatic(int types, RouteInfo route) { 299b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn if (sStatic.mSelectedRoute == route) return; 3000d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell if ((route.getSupportedTypes() & types) == 0) { 3010d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell Log.w(TAG, "selectRoute ignored; cannot select route with supported types " + 3020d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell typesToString(route.getSupportedTypes()) + " into route types " + 3030d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell typesToString(types)); 3044ee1f55ce0f4909a7430ab44563a81852f335071Adam Powell return; 3050d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell } 3069a1de308cea2d160778fd977825f10a07b49d738Adam Powell 307dd0a19266d5c837069da1ea188744d54c8d723a8Adam Powell final RouteInfo btRoute = sStatic.mBluetoothA2dpRoute; 308dd0a19266d5c837069da1ea188744d54c8d723a8Adam Powell if (btRoute != null && (types & ROUTE_TYPE_LIVE_AUDIO) != 0 && 309dd0a19266d5c837069da1ea188744d54c8d723a8Adam Powell (route == btRoute || route == sStatic.mDefaultAudio)) { 310dd0a19266d5c837069da1ea188744d54c8d723a8Adam Powell try { 311dd0a19266d5c837069da1ea188744d54c8d723a8Adam Powell sStatic.mAudioService.setBluetoothA2dpOn(route == btRoute); 312dd0a19266d5c837069da1ea188744d54c8d723a8Adam Powell } catch (RemoteException e) { 313dd0a19266d5c837069da1ea188744d54c8d723a8Adam Powell Log.e(TAG, "Error changing Bluetooth A2DP state", e); 314dd0a19266d5c837069da1ea188744d54c8d723a8Adam Powell } 315dd0a19266d5c837069da1ea188744d54c8d723a8Adam Powell } 316dd0a19266d5c837069da1ea188744d54c8d723a8Adam Powell 317b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn if (sStatic.mSelectedRoute != null) { 3189a1de308cea2d160778fd977825f10a07b49d738Adam Powell // TODO filter types properly 319b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn dispatchRouteUnselected(types & sStatic.mSelectedRoute.getSupportedTypes(), 320b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn sStatic.mSelectedRoute); 3219a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 322b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn sStatic.mSelectedRoute = route; 3239a1de308cea2d160778fd977825f10a07b49d738Adam Powell if (route != null) { 3249a1de308cea2d160778fd977825f10a07b49d738Adam Powell // TODO filter types properly 3259a1de308cea2d160778fd977825f10a07b49d738Adam Powell dispatchRouteSelected(types & route.getSupportedTypes(), route); 3269a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 3279a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 3289a1de308cea2d160778fd977825f10a07b49d738Adam Powell 3299a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 3309a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Add an app-specified route for media to the MediaRouter. 3319a1de308cea2d160778fd977825f10a07b49d738Adam Powell * App-specified route definitions are created using {@link #createUserRoute(RouteCategory)} 3329a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 3339a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param info Definition of the route to add 3349a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @see #createUserRoute() 3359a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @see #removeUserRoute(UserRouteInfo) 3369a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 3379a1de308cea2d160778fd977825f10a07b49d738Adam Powell public void addUserRoute(UserRouteInfo info) { 3389a1de308cea2d160778fd977825f10a07b49d738Adam Powell addRoute(info); 3399a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 3409a1de308cea2d160778fd977825f10a07b49d738Adam Powell 341d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell /** 342d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell * @hide Framework use only 343d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell */ 344d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell public void addRouteInt(RouteInfo info) { 345d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell addRoute(info); 346d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell } 347d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell 348b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn static void addRoute(RouteInfo info) { 3499a1de308cea2d160778fd977825f10a07b49d738Adam Powell final RouteCategory cat = info.getCategory(); 350b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn if (!sStatic.mCategories.contains(cat)) { 351b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn sStatic.mCategories.add(cat); 3529a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 353b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn final boolean onlyRoute = sStatic.mRoutes.isEmpty(); 354d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell if (cat.isGroupable() && !(info instanceof RouteGroup)) { 3559a1de308cea2d160778fd977825f10a07b49d738Adam Powell // Enforce that any added route in a groupable category must be in a group. 3569a1de308cea2d160778fd977825f10a07b49d738Adam Powell final RouteGroup group = new RouteGroup(info.getCategory()); 357dbbfa702a09f6d2d36dee1b552442d04a4673f89Adam Powell group.mSupportedTypes = info.mSupportedTypes; 358b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn sStatic.mRoutes.add(group); 359d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell dispatchRouteAdded(group); 360b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell group.addRoute(info); 361d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell 3629a1de308cea2d160778fd977825f10a07b49d738Adam Powell info = group; 363d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell } else { 364b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn sStatic.mRoutes.add(info); 365d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell dispatchRouteAdded(info); 3669a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 367d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell 3689a1de308cea2d160778fd977825f10a07b49d738Adam Powell if (onlyRoute) { 369b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn selectRouteStatic(info.getSupportedTypes(), info); 3709a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 3719a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 3729a1de308cea2d160778fd977825f10a07b49d738Adam Powell 3739a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 3749a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Remove an app-specified route for media from the MediaRouter. 3759a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 3769a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param info Definition of the route to remove 3779a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @see #addUserRoute(UserRouteInfo) 3789a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 3799a1de308cea2d160778fd977825f10a07b49d738Adam Powell public void removeUserRoute(UserRouteInfo info) { 3809a1de308cea2d160778fd977825f10a07b49d738Adam Powell removeRoute(info); 3819a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 3829a1de308cea2d160778fd977825f10a07b49d738Adam Powell 383690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell /** 384690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell * Remove all app-specified routes from the MediaRouter. 385690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell * 386690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell * @see #removeUserRoute(UserRouteInfo) 387690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell */ 388690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell public void clearUserRoutes() { 389b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn for (int i = 0; i < sStatic.mRoutes.size(); i++) { 390b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn final RouteInfo info = sStatic.mRoutes.get(i); 391d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell // TODO Right now, RouteGroups only ever contain user routes. 392d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell // The code below will need to change if this assumption does. 393d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell if (info instanceof UserRouteInfo || info instanceof RouteGroup) { 394690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell removeRouteAt(i); 395690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell i--; 396690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell } 397690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell } 398690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell } 399690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell 400d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell /** 401d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell * @hide internal use only 402d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell */ 403d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell public void removeRouteInt(RouteInfo info) { 404d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell removeRoute(info); 405d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell } 406d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell 407b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn static void removeRoute(RouteInfo info) { 408b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn if (sStatic.mRoutes.remove(info)) { 4099a1de308cea2d160778fd977825f10a07b49d738Adam Powell final RouteCategory removingCat = info.getCategory(); 410b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn final int count = sStatic.mRoutes.size(); 4119a1de308cea2d160778fd977825f10a07b49d738Adam Powell boolean found = false; 4129a1de308cea2d160778fd977825f10a07b49d738Adam Powell for (int i = 0; i < count; i++) { 413b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn final RouteCategory cat = sStatic.mRoutes.get(i).getCategory(); 4149a1de308cea2d160778fd977825f10a07b49d738Adam Powell if (removingCat == cat) { 4159a1de308cea2d160778fd977825f10a07b49d738Adam Powell found = true; 4169a1de308cea2d160778fd977825f10a07b49d738Adam Powell break; 4179a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 4189a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 419d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell if (info == sStatic.mSelectedRoute) { 420d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell // Removing the currently selected route? Select the default before we remove it. 421d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell // TODO: Be smarter about the route types here; this selects for all valid. 422d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell selectRouteStatic(ROUTE_TYPE_LIVE_AUDIO | ROUTE_TYPE_USER, sStatic.mDefaultAudio); 423d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell } 4249a1de308cea2d160778fd977825f10a07b49d738Adam Powell if (!found) { 425b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn sStatic.mCategories.remove(removingCat); 4269a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 4279a1de308cea2d160778fd977825f10a07b49d738Adam Powell dispatchRouteRemoved(info); 4289a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 4299a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 4309a1de308cea2d160778fd977825f10a07b49d738Adam Powell 431690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell void removeRouteAt(int routeIndex) { 432b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn if (routeIndex >= 0 && routeIndex < sStatic.mRoutes.size()) { 433b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn final RouteInfo info = sStatic.mRoutes.remove(routeIndex); 434690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell final RouteCategory removingCat = info.getCategory(); 435b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn final int count = sStatic.mRoutes.size(); 436690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell boolean found = false; 437690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell for (int i = 0; i < count; i++) { 438b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn final RouteCategory cat = sStatic.mRoutes.get(i).getCategory(); 439690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell if (removingCat == cat) { 440690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell found = true; 441690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell break; 442690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell } 443690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell } 444d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell if (info == sStatic.mSelectedRoute) { 445d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell // Removing the currently selected route? Select the default before we remove it. 446d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell // TODO: Be smarter about the route types here; this selects for all valid. 447d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell selectRouteStatic(ROUTE_TYPE_LIVE_AUDIO | ROUTE_TYPE_USER, sStatic.mDefaultAudio); 448d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell } 449690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell if (!found) { 450b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn sStatic.mCategories.remove(removingCat); 451690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell } 452690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell dispatchRouteRemoved(info); 453690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell } 454690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell } 455690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell 4569a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 4579a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Return the number of {@link MediaRouter.RouteCategory categories} currently 4589a1de308cea2d160778fd977825f10a07b49d738Adam Powell * represented by routes known to this MediaRouter. 4599a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 4609a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @return the number of unique categories represented by this MediaRouter's known routes 4619a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 4629a1de308cea2d160778fd977825f10a07b49d738Adam Powell public int getCategoryCount() { 463b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn return sStatic.mCategories.size(); 4649a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 4659a1de308cea2d160778fd977825f10a07b49d738Adam Powell 4669a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 4679a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Return the {@link MediaRouter.RouteCategory category} at the given index. 4689a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Valid indices are in the range [0-getCategoryCount). 4699a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 4709a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param index which category to return 4719a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @return the category at index 4729a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 4739a1de308cea2d160778fd977825f10a07b49d738Adam Powell public RouteCategory getCategoryAt(int index) { 474b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn return sStatic.mCategories.get(index); 4759a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 4769a1de308cea2d160778fd977825f10a07b49d738Adam Powell 4779a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 4789a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Return the number of {@link MediaRouter.RouteInfo routes} currently known 4799a1de308cea2d160778fd977825f10a07b49d738Adam Powell * to this MediaRouter. 4809a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 4819a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @return the number of routes tracked by this router 4829a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 4839a1de308cea2d160778fd977825f10a07b49d738Adam Powell public int getRouteCount() { 484b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn return sStatic.mRoutes.size(); 4859a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 4869a1de308cea2d160778fd977825f10a07b49d738Adam Powell 4879a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 4889a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Return the route at the specified index. 4899a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 4909a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param index index of the route to return 4919a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @return the route at index 4929a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 4939a1de308cea2d160778fd977825f10a07b49d738Adam Powell public RouteInfo getRouteAt(int index) { 494b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn return sStatic.mRoutes.get(index); 495b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn } 496b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn 497b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn static int getRouteCountStatic() { 498b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn return sStatic.mRoutes.size(); 499b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn } 500b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn 501b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn static RouteInfo getRouteAtStatic(int index) { 502b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn return sStatic.mRoutes.get(index); 5039a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 5049a1de308cea2d160778fd977825f10a07b49d738Adam Powell 5059a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 5069a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Create a new user route that may be modified and registered for use by the application. 5079a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 5089a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param category The category the new route will belong to 5099a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @return A new UserRouteInfo for use by the application 5109a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 5119a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @see #addUserRoute(UserRouteInfo) 5129a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @see #removeUserRoute(UserRouteInfo) 5139a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @see #createRouteCategory(CharSequence) 5149a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 5159a1de308cea2d160778fd977825f10a07b49d738Adam Powell public UserRouteInfo createUserRoute(RouteCategory category) { 5169a1de308cea2d160778fd977825f10a07b49d738Adam Powell return new UserRouteInfo(category); 5179a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 5189a1de308cea2d160778fd977825f10a07b49d738Adam Powell 5199a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 5209a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Create a new route category. Each route must belong to a category. 5219a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 5229a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param name Name of the new category 5239a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param isGroupable true if routes in this category may be grouped with one another 5249a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @return the new RouteCategory 5259a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 5269a1de308cea2d160778fd977825f10a07b49d738Adam Powell public RouteCategory createRouteCategory(CharSequence name, boolean isGroupable) { 5279a1de308cea2d160778fd977825f10a07b49d738Adam Powell return new RouteCategory(name, ROUTE_TYPE_USER, isGroupable); 5289a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 5290d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell 5300d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell /** 5310d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * Create a new route category. Each route must belong to a category. 5320d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * 5330d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * @param nameResId Resource ID of the name of the new category 5340d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * @param isGroupable true if routes in this category may be grouped with one another 5350d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * @return the new RouteCategory 5360d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell */ 5370d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public RouteCategory createRouteCategory(int nameResId, boolean isGroupable) { 5380d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell return new RouteCategory(nameResId, ROUTE_TYPE_USER, isGroupable); 5390d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell } 5409a1de308cea2d160778fd977825f10a07b49d738Adam Powell 541b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn static void updateRoute(final RouteInfo info) { 5429a1de308cea2d160778fd977825f10a07b49d738Adam Powell dispatchRouteChanged(info); 5439a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 5449a1de308cea2d160778fd977825f10a07b49d738Adam Powell 545b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn static void dispatchRouteSelected(int type, RouteInfo info) { 54639d5c6172503620ac3761148adac5fd7fa20d02dAdam Powell for (CallbackInfo cbi : sStatic.mCallbacks) { 5479a1de308cea2d160778fd977825f10a07b49d738Adam Powell if ((cbi.type & type) != 0) { 548b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn cbi.cb.onRouteSelected(cbi.router, type, info); 5499a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 5509a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 5519a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 5529a1de308cea2d160778fd977825f10a07b49d738Adam Powell 553b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn static void dispatchRouteUnselected(int type, RouteInfo info) { 55439d5c6172503620ac3761148adac5fd7fa20d02dAdam Powell for (CallbackInfo cbi : sStatic.mCallbacks) { 5559a1de308cea2d160778fd977825f10a07b49d738Adam Powell if ((cbi.type & type) != 0) { 556b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn cbi.cb.onRouteUnselected(cbi.router, type, info); 5579a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 5589a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 5599a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 5609a1de308cea2d160778fd977825f10a07b49d738Adam Powell 561b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn static void dispatchRouteChanged(RouteInfo info) { 56239d5c6172503620ac3761148adac5fd7fa20d02dAdam Powell for (CallbackInfo cbi : sStatic.mCallbacks) { 5639a1de308cea2d160778fd977825f10a07b49d738Adam Powell if ((cbi.type & info.mSupportedTypes) != 0) { 564b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn cbi.cb.onRouteChanged(cbi.router, info); 5659a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 5669a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 5679a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 5689a1de308cea2d160778fd977825f10a07b49d738Adam Powell 569b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn static void dispatchRouteAdded(RouteInfo info) { 57039d5c6172503620ac3761148adac5fd7fa20d02dAdam Powell for (CallbackInfo cbi : sStatic.mCallbacks) { 5719a1de308cea2d160778fd977825f10a07b49d738Adam Powell if ((cbi.type & info.mSupportedTypes) != 0) { 572b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn cbi.cb.onRouteAdded(cbi.router, info); 5739a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 5749a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 5759a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 5769a1de308cea2d160778fd977825f10a07b49d738Adam Powell 577b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn static void dispatchRouteRemoved(RouteInfo info) { 57839d5c6172503620ac3761148adac5fd7fa20d02dAdam Powell for (CallbackInfo cbi : sStatic.mCallbacks) { 5799a1de308cea2d160778fd977825f10a07b49d738Adam Powell if ((cbi.type & info.mSupportedTypes) != 0) { 580b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn cbi.cb.onRouteRemoved(cbi.router, info); 5819a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 5829a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 5839a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 5849a1de308cea2d160778fd977825f10a07b49d738Adam Powell 585b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn static void dispatchRouteGrouped(RouteInfo info, RouteGroup group, int index) { 58639d5c6172503620ac3761148adac5fd7fa20d02dAdam Powell for (CallbackInfo cbi : sStatic.mCallbacks) { 587d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell if ((cbi.type & group.mSupportedTypes) != 0) { 588b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn cbi.cb.onRouteGrouped(cbi.router, info, group, index); 589d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell } 590d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell } 591d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell } 592d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell 593b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn static void dispatchRouteUngrouped(RouteInfo info, RouteGroup group) { 59439d5c6172503620ac3761148adac5fd7fa20d02dAdam Powell for (CallbackInfo cbi : sStatic.mCallbacks) { 595d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell if ((cbi.type & group.mSupportedTypes) != 0) { 596b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn cbi.cb.onRouteUngrouped(cbi.router, info, group); 5979a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 5989a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 5999a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 6009a1de308cea2d160778fd977825f10a07b49d738Adam Powell 6018e37a85bf3dc39519942698dc90a3951306b934bAdam Powell static void dispatchRouteVolumeChanged(RouteInfo info) { 6028e37a85bf3dc39519942698dc90a3951306b934bAdam Powell for (CallbackInfo cbi : sStatic.mCallbacks) { 6038e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if ((cbi.type & info.mSupportedTypes) != 0) { 6048e37a85bf3dc39519942698dc90a3951306b934bAdam Powell cbi.cb.onRouteVolumeChanged(cbi.router, info); 6058e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 6068e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 6078e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 6088e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 6098e37a85bf3dc39519942698dc90a3951306b934bAdam Powell static void systemVolumeChanged(int newValue) { 6108e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final RouteInfo selectedRoute = sStatic.mSelectedRoute; 6118e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (selectedRoute == null) return; 6128e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 6138e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (selectedRoute == sStatic.mBluetoothA2dpRoute || 6148e37a85bf3dc39519942698dc90a3951306b934bAdam Powell selectedRoute == sStatic.mDefaultAudio) { 6158e37a85bf3dc39519942698dc90a3951306b934bAdam Powell dispatchRouteVolumeChanged(selectedRoute); 6168e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } else if (sStatic.mBluetoothA2dpRoute != null) { 6178e37a85bf3dc39519942698dc90a3951306b934bAdam Powell try { 6188e37a85bf3dc39519942698dc90a3951306b934bAdam Powell dispatchRouteVolumeChanged(sStatic.mAudioService.isBluetoothA2dpOn() ? 6198e37a85bf3dc39519942698dc90a3951306b934bAdam Powell sStatic.mBluetoothA2dpRoute : sStatic.mDefaultAudio); 6208e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } catch (RemoteException e) { 6218e37a85bf3dc39519942698dc90a3951306b934bAdam Powell Log.e(TAG, "Error checking Bluetooth A2DP state to report volume change", e); 6228e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 6238e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } else { 6248e37a85bf3dc39519942698dc90a3951306b934bAdam Powell dispatchRouteVolumeChanged(sStatic.mDefaultAudio); 6258e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 6268e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 6278e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 6289a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 6299a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Information about a media route. 6309a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 631b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn public static class RouteInfo { 6329a1de308cea2d160778fd977825f10a07b49d738Adam Powell CharSequence mName; 6330d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell int mNameResId; 6349a1de308cea2d160778fd977825f10a07b49d738Adam Powell private CharSequence mStatus; 6359a1de308cea2d160778fd977825f10a07b49d738Adam Powell int mSupportedTypes; 6369a1de308cea2d160778fd977825f10a07b49d738Adam Powell RouteGroup mGroup; 6379a1de308cea2d160778fd977825f10a07b49d738Adam Powell final RouteCategory mCategory; 638ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell Drawable mIcon; 6391357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi // playback information 6401357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi int mPlaybackType = PLAYBACK_TYPE_LOCAL; 6411357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi int mVolumeMax = RemoteControlClient.DEFAULT_PLAYBACK_VOLUME; 6421357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi int mVolume = RemoteControlClient.DEFAULT_PLAYBACK_VOLUME; 6431357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi int mVolumeHandling = RemoteControlClient.DEFAULT_PLAYBACK_VOLUME_HANDLING; 6441357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi int mPlaybackStream = AudioManager.STREAM_MUSIC; 6451357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi VolumeCallbackInfo mVcb; 6469a1de308cea2d160778fd977825f10a07b49d738Adam Powell 647b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell private Object mTag; 648b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell 6491357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 6501357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * The default playback type, "local", indicating the presentation of the media is happening 6511357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * on the same device (e.g. a phone, a tablet) as where it is controlled from. 6521357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @see #setPlaybackType(int) 6531357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 6541357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public final static int PLAYBACK_TYPE_LOCAL = 0; 6551357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 6561357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * A playback type indicating the presentation of the media is happening on 6571357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * a different device (i.e. the remote device) than where it is controlled from. 6581357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @see #setPlaybackType(int) 6591357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 6601357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public final static int PLAYBACK_TYPE_REMOTE = 1; 6611357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 6621357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * Playback information indicating the playback volume is fixed, i.e. it cannot be 6631357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * controlled from this object. An example of fixed playback volume is a remote player, 6641357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * playing over HDMI where the user prefers to control the volume on the HDMI sink, rather 6651357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * than attenuate at the source. 6661357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @see #setVolumeHandling(int) 6671357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 6681357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public final static int PLAYBACK_VOLUME_FIXED = 0; 6691357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 6701357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * Playback information indicating the playback volume is variable and can be controlled 6711357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * from this object. 6721357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 6731357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public final static int PLAYBACK_VOLUME_VARIABLE = 1; 6741357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 6759a1de308cea2d160778fd977825f10a07b49d738Adam Powell RouteInfo(RouteCategory category) { 6769a1de308cea2d160778fd977825f10a07b49d738Adam Powell mCategory = category; 6779a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 6789a1de308cea2d160778fd977825f10a07b49d738Adam Powell 6799a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 6809a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @return The user-friendly name of a media route. This is the string presented 6819a1de308cea2d160778fd977825f10a07b49d738Adam Powell * to users who may select this as the active route. 6829a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 6839a1de308cea2d160778fd977825f10a07b49d738Adam Powell public CharSequence getName() { 6840d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell return getName(sStatic.mResources); 6850d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell } 6860d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell 6870d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell /** 6880d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * Return the properly localized/resource selected name of this route. 6890d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * 6900d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * @param context Context used to resolve the correct configuration to load 6910d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * @return The user-friendly name of the media route. This is the string presented 6920d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * to users who may select this as the active route. 6930d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell */ 6940d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public CharSequence getName(Context context) { 6950d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell return getName(context.getResources()); 6960d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell } 6970d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell 6980d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell CharSequence getName(Resources res) { 6990d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell if (mNameResId != 0) { 7000d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell return mName = res.getText(mNameResId); 7010d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell } 7029a1de308cea2d160778fd977825f10a07b49d738Adam Powell return mName; 7039a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 7049a1de308cea2d160778fd977825f10a07b49d738Adam Powell 7059a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 7069a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @return The user-friendly status for a media route. This may include a description 7079a1de308cea2d160778fd977825f10a07b49d738Adam Powell * of the currently playing media, if available. 7089a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 7099a1de308cea2d160778fd977825f10a07b49d738Adam Powell public CharSequence getStatus() { 7109a1de308cea2d160778fd977825f10a07b49d738Adam Powell return mStatus; 7119a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 7129a1de308cea2d160778fd977825f10a07b49d738Adam Powell 7139a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 7149a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @return A media type flag set describing which types this route supports. 7159a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 7169a1de308cea2d160778fd977825f10a07b49d738Adam Powell public int getSupportedTypes() { 7179a1de308cea2d160778fd977825f10a07b49d738Adam Powell return mSupportedTypes; 7189a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 7199a1de308cea2d160778fd977825f10a07b49d738Adam Powell 7209a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 7219a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @return The group that this route belongs to. 7229a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 7239a1de308cea2d160778fd977825f10a07b49d738Adam Powell public RouteGroup getGroup() { 7249a1de308cea2d160778fd977825f10a07b49d738Adam Powell return mGroup; 7259a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 7269a1de308cea2d160778fd977825f10a07b49d738Adam Powell 7279a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 7289a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @return the category this route belongs to. 7299a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 7309a1de308cea2d160778fd977825f10a07b49d738Adam Powell public RouteCategory getCategory() { 7319a1de308cea2d160778fd977825f10a07b49d738Adam Powell return mCategory; 7329a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 7339a1de308cea2d160778fd977825f10a07b49d738Adam Powell 734ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell /** 735ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * Get the icon representing this route. 736ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * This icon will be used in picker UIs if available. 737ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * 738ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * @return the icon representing this route or null if no icon is available 739ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell */ 740ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell public Drawable getIconDrawable() { 741ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell return mIcon; 742ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell } 743ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell 744b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell /** 745b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell * Set an application-specific tag object for this route. 746b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell * The application may use this to store arbitrary data associated with the 747b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell * route for internal tracking. 748b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell * 749b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell * <p>Note that the lifespan of a route may be well past the lifespan of 750b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell * an Activity or other Context; take care that objects you store here 751b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell * will not keep more data in memory alive than you intend.</p> 752b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell * 753b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell * @param tag Arbitrary, app-specific data for this route to hold for later use 754b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell */ 755b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell public void setTag(Object tag) { 756b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell mTag = tag; 757130b4572d1f3df702e5b296a655d15a41f6d4c66Adam Powell routeUpdated(); 758b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell } 759b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell 760b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell /** 761b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell * @return The tag object previously set by the application 762b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell * @see #setTag(Object) 763b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell */ 764b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell public Object getTag() { 765b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell return mTag; 766b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell } 767b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell 7681357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 7691357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @return the type of playback associated with this route 7701357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @see UserRouteInfo#setPlaybackType(int) 7711357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 7721357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public int getPlaybackType() { 7731357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi return mPlaybackType; 7741357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 7751357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 7761357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 7771357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @return the stream over which the playback associated with this route is performed 7781357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @see UserRouteInfo#setPlaybackStream(int) 7791357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 7801357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public int getPlaybackStream() { 7811357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi return mPlaybackStream; 7821357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 7831357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 7841357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 7858e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * Return the current volume for this route. Depending on the route, this may only 7868e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * be valid if the route is currently selected. 7878e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * 7881357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @return the volume at which the playback associated with this route is performed 7891357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @see UserRouteInfo#setVolume(int) 7901357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 7911357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public int getVolume() { 7921357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi if (mPlaybackType == PLAYBACK_TYPE_LOCAL) { 7931357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi int vol = 0; 7941357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi try { 7951357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi vol = sStatic.mAudioService.getStreamVolume(mPlaybackStream); 7961357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } catch (RemoteException e) { 7971357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi Log.e(TAG, "Error getting local stream volume", e); 7981357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 7991357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi return vol; 8001357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } else { 8011357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi return mVolume; 8021357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 8031357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 8041357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 8051357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 8068e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * Request a volume change for this route. 8078e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * @param volume value between 0 and getVolumeMax 8088e37a85bf3dc39519942698dc90a3951306b934bAdam Powell */ 8098e37a85bf3dc39519942698dc90a3951306b934bAdam Powell public void requestSetVolume(int volume) { 8108e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (mPlaybackType == PLAYBACK_TYPE_LOCAL) { 8118e37a85bf3dc39519942698dc90a3951306b934bAdam Powell try { 8128e37a85bf3dc39519942698dc90a3951306b934bAdam Powell sStatic.mAudioService.setStreamVolume(mPlaybackStream, volume, 0); 8138e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } catch (RemoteException e) { 8148e37a85bf3dc39519942698dc90a3951306b934bAdam Powell Log.e(TAG, "Error setting local stream volume", e); 8158e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 8168e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } else { 8178e37a85bf3dc39519942698dc90a3951306b934bAdam Powell Log.e(TAG, getClass().getSimpleName() + ".requestSetVolume(): " + 8188e37a85bf3dc39519942698dc90a3951306b934bAdam Powell "Non-local volume playback on system route? " + 8198e37a85bf3dc39519942698dc90a3951306b934bAdam Powell "Could not request volume change."); 8208e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 8218e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 8228e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 8238e37a85bf3dc39519942698dc90a3951306b934bAdam Powell /** 8248e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * Request an incremental volume update for this route. 8258e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * @param direction Delta to apply to the current volume 8268e37a85bf3dc39519942698dc90a3951306b934bAdam Powell */ 8278e37a85bf3dc39519942698dc90a3951306b934bAdam Powell public void requestUpdateVolume(int direction) { 8288e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (mPlaybackType == PLAYBACK_TYPE_LOCAL) { 8298e37a85bf3dc39519942698dc90a3951306b934bAdam Powell try { 8308e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final int volume = 8318e37a85bf3dc39519942698dc90a3951306b934bAdam Powell Math.max(0, Math.min(getVolume() + direction, getVolumeMax())); 8328e37a85bf3dc39519942698dc90a3951306b934bAdam Powell sStatic.mAudioService.setStreamVolume(mPlaybackStream, volume, 0); 8338e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } catch (RemoteException e) { 8348e37a85bf3dc39519942698dc90a3951306b934bAdam Powell Log.e(TAG, "Error setting local stream volume", e); 8358e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 8368e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } else { 8378e37a85bf3dc39519942698dc90a3951306b934bAdam Powell Log.e(TAG, getClass().getSimpleName() + ".requestChangeVolume(): " + 8388e37a85bf3dc39519942698dc90a3951306b934bAdam Powell "Non-local volume playback on system route? " + 8398e37a85bf3dc39519942698dc90a3951306b934bAdam Powell "Could not request volume change."); 8408e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 8418e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 8428e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 8438e37a85bf3dc39519942698dc90a3951306b934bAdam Powell /** 8441357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @return the maximum volume at which the playback associated with this route is performed 8451357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @see UserRouteInfo#setVolumeMax(int) 8461357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 8471357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public int getVolumeMax() { 8481357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi if (mPlaybackType == PLAYBACK_TYPE_LOCAL) { 8491357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi int volMax = 0; 8501357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi try { 8511357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi volMax = sStatic.mAudioService.getStreamMaxVolume(mPlaybackStream); 8521357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } catch (RemoteException e) { 8531357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi Log.e(TAG, "Error getting local stream volume", e); 8541357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 8551357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi return volMax; 8561357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } else { 8571357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi return mVolumeMax; 8581357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 8591357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 8601357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 8611357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 8621357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @return how volume is handling on the route 8631357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @see UserRouteInfo#setVolumeHandling(int) 8641357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 8651357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public int getVolumeHandling() { 8661357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi return mVolumeHandling; 8671357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 8681357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 8699a1de308cea2d160778fd977825f10a07b49d738Adam Powell void setStatusInt(CharSequence status) { 8709a1de308cea2d160778fd977825f10a07b49d738Adam Powell if (!status.equals(mStatus)) { 8719a1de308cea2d160778fd977825f10a07b49d738Adam Powell mStatus = status; 8729a1de308cea2d160778fd977825f10a07b49d738Adam Powell if (mGroup != null) { 8739a1de308cea2d160778fd977825f10a07b49d738Adam Powell mGroup.memberStatusChanged(this, status); 8749a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 8759a1de308cea2d160778fd977825f10a07b49d738Adam Powell routeUpdated(); 8769a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 8779a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 8789a1de308cea2d160778fd977825f10a07b49d738Adam Powell 8791357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi final IRemoteVolumeObserver.Stub mRemoteVolObserver = new IRemoteVolumeObserver.Stub() { 8801357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public void dispatchRemoteVolumeUpdate(final int direction, final int value) { 8811357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi sStatic.mHandler.post(new Runnable() { 8821357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi @Override 8831357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public void run() { 8841357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi //Log.d(TAG, "dispatchRemoteVolumeUpdate dir=" + direction + " val=" + value); 8851357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi if (mVcb != null) { 8861357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi if (direction != 0) { 8871357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi mVcb.vcb.onVolumeUpdateRequest(mVcb.route, direction); 8881357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } else { 8891357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi mVcb.vcb.onVolumeSetRequest(mVcb.route, value); 8901357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 8911357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 8921357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 8931357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi }); 8941357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 8951357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi }; 8961357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 8979a1de308cea2d160778fd977825f10a07b49d738Adam Powell void routeUpdated() { 8989a1de308cea2d160778fd977825f10a07b49d738Adam Powell updateRoute(this); 8999a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 9009a1de308cea2d160778fd977825f10a07b49d738Adam Powell 9019a1de308cea2d160778fd977825f10a07b49d738Adam Powell @Override 9029a1de308cea2d160778fd977825f10a07b49d738Adam Powell public String toString() { 903d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell String supportedTypes = typesToString(getSupportedTypes()); 904d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell return getClass().getSimpleName() + "{ name=" + getName() + ", status=" + getStatus() + 905d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell " category=" + getCategory() + 9069a1de308cea2d160778fd977825f10a07b49d738Adam Powell " supportedTypes=" + supportedTypes + "}"; 9079a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 9089a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 9099a1de308cea2d160778fd977825f10a07b49d738Adam Powell 9109a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 9119a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Information about a route that the application may define and modify. 9128e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * A user route defaults to {@link RouteInfo#PLAYBACK_TYPE_REMOTE} and 9138e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * {@link RouteInfo#PLAYBACK_VOLUME_FIXED}. 9149a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 9159a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @see MediaRouter.RouteInfo 9169a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 917b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn public static class UserRouteInfo extends RouteInfo { 918ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell RemoteControlClient mRcc; 9199a1de308cea2d160778fd977825f10a07b49d738Adam Powell 9209a1de308cea2d160778fd977825f10a07b49d738Adam Powell UserRouteInfo(RouteCategory category) { 9219a1de308cea2d160778fd977825f10a07b49d738Adam Powell super(category); 9229a1de308cea2d160778fd977825f10a07b49d738Adam Powell mSupportedTypes = ROUTE_TYPE_USER; 9238e37a85bf3dc39519942698dc90a3951306b934bAdam Powell mPlaybackType = PLAYBACK_TYPE_REMOTE; 9248e37a85bf3dc39519942698dc90a3951306b934bAdam Powell mVolumeHandling = PLAYBACK_VOLUME_FIXED; 9259a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 9269a1de308cea2d160778fd977825f10a07b49d738Adam Powell 9279a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 9289a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Set the user-visible name of this route. 9299a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param name Name to display to the user to describe this route 9309a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 9319a1de308cea2d160778fd977825f10a07b49d738Adam Powell public void setName(CharSequence name) { 9329a1de308cea2d160778fd977825f10a07b49d738Adam Powell mName = name; 9339a1de308cea2d160778fd977825f10a07b49d738Adam Powell routeUpdated(); 9349a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 9350d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell 9360d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell /** 9370d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * Set the user-visible name of this route. 9380d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * @param resId Resource ID of the name to display to the user to describe this route 9390d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell */ 9400d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public void setName(int resId) { 9410d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell mNameResId = resId; 9420d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell mName = null; 9430d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell routeUpdated(); 9440d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell } 9459a1de308cea2d160778fd977825f10a07b49d738Adam Powell 9469a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 9479a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Set the current user-visible status for this route. 9489a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param status Status to display to the user to describe what the endpoint 9499a1de308cea2d160778fd977825f10a07b49d738Adam Powell * of this route is currently doing 9509a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 9519a1de308cea2d160778fd977825f10a07b49d738Adam Powell public void setStatus(CharSequence status) { 9529a1de308cea2d160778fd977825f10a07b49d738Adam Powell setStatusInt(status); 9539a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 954ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell 955ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell /** 956ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * Set the RemoteControlClient responsible for reporting playback info for this 957ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * user route. 958ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * 959ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * <p>If this route manages remote playback, the data exposed by this 960ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * RemoteControlClient will be used to reflect and update information 961ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * such as route volume info in related UIs.</p> 962ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * 9631357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * <p>The RemoteControlClient must have been previously registered with 9641357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * {@link AudioManager#registerRemoteControlClient(RemoteControlClient)}.</p> 9651357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * 966ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * @param rcc RemoteControlClient associated with this route 967ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell */ 968ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell public void setRemoteControlClient(RemoteControlClient rcc) { 969ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell mRcc = rcc; 9701357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi updatePlaybackInfoOnRcc(); 971ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell } 972ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell 973ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell /** 9744599696591f745b3a546197d2ba7e5cfc5562484Adam Powell * Retrieve the RemoteControlClient associated with this route, if one has been set. 9754599696591f745b3a546197d2ba7e5cfc5562484Adam Powell * 9764599696591f745b3a546197d2ba7e5cfc5562484Adam Powell * @return the RemoteControlClient associated with this route 9774599696591f745b3a546197d2ba7e5cfc5562484Adam Powell * @see #setRemoteControlClient(RemoteControlClient) 9784599696591f745b3a546197d2ba7e5cfc5562484Adam Powell */ 9794599696591f745b3a546197d2ba7e5cfc5562484Adam Powell public RemoteControlClient getRemoteControlClient() { 9804599696591f745b3a546197d2ba7e5cfc5562484Adam Powell return mRcc; 9814599696591f745b3a546197d2ba7e5cfc5562484Adam Powell } 9824599696591f745b3a546197d2ba7e5cfc5562484Adam Powell 9834599696591f745b3a546197d2ba7e5cfc5562484Adam Powell /** 984ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * Set an icon that will be used to represent this route. 985ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * The system may use this icon in picker UIs or similar. 986ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * 987ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * @param icon icon drawable to use to represent this route 988ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell */ 989ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell public void setIconDrawable(Drawable icon) { 990ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell mIcon = icon; 991ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell } 992ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell 993ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell /** 994ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * Set an icon that will be used to represent this route. 995ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * The system may use this icon in picker UIs or similar. 996ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * 99771c69897ad0a55d590698bfa399bfe99c763b9dbAdam Powell * @param resId Resource ID of an icon drawable to use to represent this route 998ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell */ 999ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell public void setIconResource(int resId) { 1000ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell setIconDrawable(sStatic.mResources.getDrawable(resId)); 1001ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell } 10021357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 10031357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 10041357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * Set a callback to be notified of volume update requests 10051357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @param vcb 10061357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 10071357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public void setVolumeCallback(VolumeCallback vcb) { 10081357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi mVcb = new VolumeCallbackInfo(vcb, this); 10091357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 10101357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 10111357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 10121357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * Defines whether playback associated with this route is "local" 10131357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * ({@link RouteInfo#PLAYBACK_TYPE_LOCAL}) or "remote" 10141357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * ({@link RouteInfo#PLAYBACK_TYPE_REMOTE}). 10151357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @param type 10161357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 10171357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public void setPlaybackType(int type) { 10181357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi if (mPlaybackType != type) { 10191357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi mPlaybackType = type; 10201357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi setPlaybackInfoOnRcc(RemoteControlClient.PLAYBACKINFO_PLAYBACK_TYPE, type); 10211357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 10221357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 10231357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 10241357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 10251357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * Defines whether volume for the playback associated with this route is fixed 10261357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * ({@link RouteInfo#PLAYBACK_VOLUME_FIXED}) or can modified 10271357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * ({@link RouteInfo#PLAYBACK_VOLUME_VARIABLE}). 10281357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @param volumeHandling 10291357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 10301357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public void setVolumeHandling(int volumeHandling) { 10311357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi if (mVolumeHandling != volumeHandling) { 10321357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi mVolumeHandling = volumeHandling; 10331357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi setPlaybackInfoOnRcc( 10341357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi RemoteControlClient.PLAYBACKINFO_VOLUME_HANDLING, volumeHandling); 10351357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 10361357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 10371357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 10381357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 10391357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * Defines at what volume the playback associated with this route is performed (for user 10401357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * feedback purposes). This information is only used when the playback is not local. 10411357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @param volume 10421357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 10431357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public void setVolume(int volume) { 10448e37a85bf3dc39519942698dc90a3951306b934bAdam Powell volume = Math.max(0, Math.min(volume, getVolumeMax())); 10451357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi if (mVolume != volume) { 10461357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi mVolume = volume; 10471357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi setPlaybackInfoOnRcc(RemoteControlClient.PLAYBACKINFO_VOLUME, volume); 10488e37a85bf3dc39519942698dc90a3951306b934bAdam Powell dispatchRouteVolumeChanged(this); 1049f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell if (mGroup != null) { 1050f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell mGroup.memberVolumeChanged(this); 1051f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell } 10528e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 10538e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 10548e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 10558e37a85bf3dc39519942698dc90a3951306b934bAdam Powell @Override 10568e37a85bf3dc39519942698dc90a3951306b934bAdam Powell public void requestSetVolume(int volume) { 10578e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (mVolumeHandling == PLAYBACK_VOLUME_VARIABLE) { 10588e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (mVcb == null) { 10598e37a85bf3dc39519942698dc90a3951306b934bAdam Powell Log.e(TAG, "Cannot requestSetVolume on user route - no volume callback set"); 10608e37a85bf3dc39519942698dc90a3951306b934bAdam Powell return; 10618e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 10628e37a85bf3dc39519942698dc90a3951306b934bAdam Powell mVcb.vcb.onVolumeSetRequest(this, volume); 10638e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 10648e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 10658e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 10668e37a85bf3dc39519942698dc90a3951306b934bAdam Powell @Override 10678e37a85bf3dc39519942698dc90a3951306b934bAdam Powell public void requestUpdateVolume(int direction) { 10688e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (mVolumeHandling == PLAYBACK_VOLUME_VARIABLE) { 10698e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (mVcb == null) { 10708e37a85bf3dc39519942698dc90a3951306b934bAdam Powell Log.e(TAG, "Cannot requestChangeVolume on user route - no volumec callback set"); 10718e37a85bf3dc39519942698dc90a3951306b934bAdam Powell return; 10728e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 10738e37a85bf3dc39519942698dc90a3951306b934bAdam Powell mVcb.vcb.onVolumeUpdateRequest(this, direction); 10741357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 10751357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 10761357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 10771357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 10781357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * Defines the maximum volume at which the playback associated with this route is performed 10791357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * (for user feedback purposes). This information is only used when the playback is not 10801357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * local. 10811357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @param volumeMax 10821357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 10831357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public void setVolumeMax(int volumeMax) { 10841357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi if (mVolumeMax != volumeMax) { 10851357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi mVolumeMax = volumeMax; 10861357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi setPlaybackInfoOnRcc(RemoteControlClient.PLAYBACKINFO_VOLUME_MAX, volumeMax); 10871357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 10881357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 10891357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 10901357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 10911357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * Defines over what stream type the media is presented. 10921357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @param stream 10931357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 10941357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public void setPlaybackStream(int stream) { 10951357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi if (mPlaybackStream != stream) { 10961357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi mPlaybackStream = stream; 10971357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi setPlaybackInfoOnRcc(RemoteControlClient.PLAYBACKINFO_USES_STREAM, stream); 10981357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 10991357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 11001357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 11011357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi private void updatePlaybackInfoOnRcc() { 11021357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi if ((mRcc != null) && (mRcc.getRcseId() != RemoteControlClient.RCSE_ID_UNREGISTERED)) { 11031357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi mRcc.setPlaybackInformation( 11041357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi RemoteControlClient.PLAYBACKINFO_VOLUME_MAX, mVolumeMax); 11051357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi mRcc.setPlaybackInformation( 11061357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi RemoteControlClient.PLAYBACKINFO_VOLUME, mVolume); 11071357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi mRcc.setPlaybackInformation( 11081357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi RemoteControlClient.PLAYBACKINFO_VOLUME_HANDLING, mVolumeHandling); 11091357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi mRcc.setPlaybackInformation( 11101357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi RemoteControlClient.PLAYBACKINFO_USES_STREAM, mPlaybackStream); 11111357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi mRcc.setPlaybackInformation( 11121357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi RemoteControlClient.PLAYBACKINFO_PLAYBACK_TYPE, mPlaybackType); 11131357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi // let AudioService know whom to call when remote volume needs to be updated 11141357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi try { 11151357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi sStatic.mAudioService.registerRemoteVolumeObserverForRcc( 11161357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi mRcc.getRcseId() /* rccId */, mRemoteVolObserver /* rvo */); 11171357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } catch (RemoteException e) { 11181357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi Log.e(TAG, "Error registering remote volume observer", e); 11191357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 11201357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 11211357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 11221357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 11231357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi private void setPlaybackInfoOnRcc(int what, int value) { 11241357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi if (mRcc != null) { 11251357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi mRcc.setPlaybackInformation(what, value); 11261357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 11271357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 11289a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 11299a1de308cea2d160778fd977825f10a07b49d738Adam Powell 11309a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 11319a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Information about a route that consists of multiple other routes in a group. 11329a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 1133b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn public static class RouteGroup extends RouteInfo { 11349a1de308cea2d160778fd977825f10a07b49d738Adam Powell final ArrayList<RouteInfo> mRoutes = new ArrayList<RouteInfo>(); 11359a1de308cea2d160778fd977825f10a07b49d738Adam Powell private boolean mUpdateName; 11369a1de308cea2d160778fd977825f10a07b49d738Adam Powell 11379a1de308cea2d160778fd977825f10a07b49d738Adam Powell RouteGroup(RouteCategory category) { 11389a1de308cea2d160778fd977825f10a07b49d738Adam Powell super(category); 11399a1de308cea2d160778fd977825f10a07b49d738Adam Powell mGroup = this; 11408e37a85bf3dc39519942698dc90a3951306b934bAdam Powell mVolumeHandling = PLAYBACK_VOLUME_FIXED; 11419a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 11429a1de308cea2d160778fd977825f10a07b49d738Adam Powell 11430d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell CharSequence getName(Resources res) { 11449a1de308cea2d160778fd977825f10a07b49d738Adam Powell if (mUpdateName) updateName(); 11450d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell return super.getName(res); 11469a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 11479a1de308cea2d160778fd977825f10a07b49d738Adam Powell 11489a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 11499a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Add a route to this group. The route must not currently belong to another group. 11509a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 11519a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param route route to add to this group 11529a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 11539a1de308cea2d160778fd977825f10a07b49d738Adam Powell public void addRoute(RouteInfo route) { 11549a1de308cea2d160778fd977825f10a07b49d738Adam Powell if (route.getGroup() != null) { 11559a1de308cea2d160778fd977825f10a07b49d738Adam Powell throw new IllegalStateException("Route " + route + " is already part of a group."); 11569a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 11579a1de308cea2d160778fd977825f10a07b49d738Adam Powell if (route.getCategory() != mCategory) { 11589a1de308cea2d160778fd977825f10a07b49d738Adam Powell throw new IllegalArgumentException( 11599a1de308cea2d160778fd977825f10a07b49d738Adam Powell "Route cannot be added to a group with a different category. " + 11609a1de308cea2d160778fd977825f10a07b49d738Adam Powell "(Route category=" + route.getCategory() + 11619a1de308cea2d160778fd977825f10a07b49d738Adam Powell " group category=" + mCategory + ")"); 11629a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 1163d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell final int at = mRoutes.size(); 11649a1de308cea2d160778fd977825f10a07b49d738Adam Powell mRoutes.add(route); 1165d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell route.mGroup = this; 11669a1de308cea2d160778fd977825f10a07b49d738Adam Powell mUpdateName = true; 1167f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell updateVolume(); 11689a1de308cea2d160778fd977825f10a07b49d738Adam Powell routeUpdated(); 1169f3b653a21cdffe04c94c275e69ecb56e00766e82Adam Powell dispatchRouteGrouped(route, this, at); 11709a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 11719a1de308cea2d160778fd977825f10a07b49d738Adam Powell 11729a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 11739a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Add a route to this group before the specified index. 11749a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 11759a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param route route to add 11769a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param insertAt insert the new route before this index 11779a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 11789a1de308cea2d160778fd977825f10a07b49d738Adam Powell public void addRoute(RouteInfo route, int insertAt) { 11799a1de308cea2d160778fd977825f10a07b49d738Adam Powell if (route.getGroup() != null) { 11809a1de308cea2d160778fd977825f10a07b49d738Adam Powell throw new IllegalStateException("Route " + route + " is already part of a group."); 11819a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 11829a1de308cea2d160778fd977825f10a07b49d738Adam Powell if (route.getCategory() != mCategory) { 11839a1de308cea2d160778fd977825f10a07b49d738Adam Powell throw new IllegalArgumentException( 11849a1de308cea2d160778fd977825f10a07b49d738Adam Powell "Route cannot be added to a group with a different category. " + 11859a1de308cea2d160778fd977825f10a07b49d738Adam Powell "(Route category=" + route.getCategory() + 11869a1de308cea2d160778fd977825f10a07b49d738Adam Powell " group category=" + mCategory + ")"); 11879a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 11889a1de308cea2d160778fd977825f10a07b49d738Adam Powell mRoutes.add(insertAt, route); 1189d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell route.mGroup = this; 11909a1de308cea2d160778fd977825f10a07b49d738Adam Powell mUpdateName = true; 1191f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell updateVolume(); 11929a1de308cea2d160778fd977825f10a07b49d738Adam Powell routeUpdated(); 1193f3b653a21cdffe04c94c275e69ecb56e00766e82Adam Powell dispatchRouteGrouped(route, this, insertAt); 11949a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 11959a1de308cea2d160778fd977825f10a07b49d738Adam Powell 11969a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 11979a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Remove a route from this group. 11989a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 11999a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param route route to remove 12009a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 12019a1de308cea2d160778fd977825f10a07b49d738Adam Powell public void removeRoute(RouteInfo route) { 12029a1de308cea2d160778fd977825f10a07b49d738Adam Powell if (route.getGroup() != this) { 12039a1de308cea2d160778fd977825f10a07b49d738Adam Powell throw new IllegalArgumentException("Route " + route + 12049a1de308cea2d160778fd977825f10a07b49d738Adam Powell " is not a member of this group."); 12059a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 12069a1de308cea2d160778fd977825f10a07b49d738Adam Powell mRoutes.remove(route); 1207d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell route.mGroup = null; 12089a1de308cea2d160778fd977825f10a07b49d738Adam Powell mUpdateName = true; 1209f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell updateVolume(); 1210d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell dispatchRouteUngrouped(route, this); 12119a1de308cea2d160778fd977825f10a07b49d738Adam Powell routeUpdated(); 12129a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 12139a1de308cea2d160778fd977825f10a07b49d738Adam Powell 12149a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 12159a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Remove the route at the specified index from this group. 12169a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 12179a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param index index of the route to remove 12189a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 12199a1de308cea2d160778fd977825f10a07b49d738Adam Powell public void removeRoute(int index) { 1220d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell RouteInfo route = mRoutes.remove(index); 1221d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell route.mGroup = null; 12229a1de308cea2d160778fd977825f10a07b49d738Adam Powell mUpdateName = true; 1223f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell updateVolume(); 1224d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell dispatchRouteUngrouped(route, this); 12259a1de308cea2d160778fd977825f10a07b49d738Adam Powell routeUpdated(); 12269a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 12279a1de308cea2d160778fd977825f10a07b49d738Adam Powell 1228d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell /** 1229d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @return The number of routes in this group 1230d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell */ 1231d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell public int getRouteCount() { 1232d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell return mRoutes.size(); 1233d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell } 1234d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell 1235d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell /** 1236d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * Return the route in this group at the specified index 1237d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * 1238d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param index Index to fetch 1239d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @return The route at index 1240d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell */ 1241d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell public RouteInfo getRouteAt(int index) { 1242d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell return mRoutes.get(index); 1243d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell } 1244d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell 1245ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell /** 1246ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * Set an icon that will be used to represent this group. 1247ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * The system may use this icon in picker UIs or similar. 1248ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * 1249ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * @param icon icon drawable to use to represent this group 1250ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell */ 1251ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell public void setIconDrawable(Drawable icon) { 1252ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell mIcon = icon; 1253ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell } 1254ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell 1255ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell /** 1256ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * Set an icon that will be used to represent this group. 1257ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * The system may use this icon in picker UIs or similar. 1258ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell * 125971c69897ad0a55d590698bfa399bfe99c763b9dbAdam Powell * @param resId Resource ID of an icon drawable to use to represent this group 1260ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell */ 1261ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell public void setIconResource(int resId) { 1262ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell setIconDrawable(sStatic.mResources.getDrawable(resId)); 1263ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell } 1264ae20ae1a8aaa013813c356ae1d9541ca7ff020aeAdam Powell 12658e37a85bf3dc39519942698dc90a3951306b934bAdam Powell @Override 12668e37a85bf3dc39519942698dc90a3951306b934bAdam Powell public void requestSetVolume(int volume) { 12678e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final int maxVol = getVolumeMax(); 12688e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (maxVol == 0) { 12698e37a85bf3dc39519942698dc90a3951306b934bAdam Powell return; 12708e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 12718e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 12728e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final float scaledVolume = (float) volume / maxVol; 12738e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final int routeCount = getRouteCount(); 12748e37a85bf3dc39519942698dc90a3951306b934bAdam Powell for (int i = 0; i < routeCount; i++) { 12758e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final RouteInfo route = getRouteAt(i); 12768e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final int routeVol = (int) (scaledVolume * route.getVolumeMax()); 12778e37a85bf3dc39519942698dc90a3951306b934bAdam Powell route.requestSetVolume(routeVol); 12788e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 12798e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (volume != mVolume) { 12808e37a85bf3dc39519942698dc90a3951306b934bAdam Powell mVolume = volume; 12818e37a85bf3dc39519942698dc90a3951306b934bAdam Powell dispatchRouteVolumeChanged(this); 12828e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 12838e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 12848e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 12858e37a85bf3dc39519942698dc90a3951306b934bAdam Powell @Override 12868e37a85bf3dc39519942698dc90a3951306b934bAdam Powell public void requestUpdateVolume(int direction) { 12878e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final int maxVol = getVolumeMax(); 12888e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (maxVol == 0) { 12898e37a85bf3dc39519942698dc90a3951306b934bAdam Powell return; 12908e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 12918e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 12928e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final int routeCount = getRouteCount(); 1293f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell int volume = 0; 12948e37a85bf3dc39519942698dc90a3951306b934bAdam Powell for (int i = 0; i < routeCount; i++) { 12958e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final RouteInfo route = getRouteAt(i); 12968e37a85bf3dc39519942698dc90a3951306b934bAdam Powell route.requestUpdateVolume(direction); 1297f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell final int routeVol = route.getVolume(); 1298f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell if (routeVol > volume) { 1299f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell volume = routeVol; 1300f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell } 13018e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 13028e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (volume != mVolume) { 13038e37a85bf3dc39519942698dc90a3951306b934bAdam Powell mVolume = volume; 13048e37a85bf3dc39519942698dc90a3951306b934bAdam Powell dispatchRouteVolumeChanged(this); 13058e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 13068e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 13078e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 13089a1de308cea2d160778fd977825f10a07b49d738Adam Powell void memberNameChanged(RouteInfo info, CharSequence name) { 13099a1de308cea2d160778fd977825f10a07b49d738Adam Powell mUpdateName = true; 13109a1de308cea2d160778fd977825f10a07b49d738Adam Powell routeUpdated(); 13119a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 13129a1de308cea2d160778fd977825f10a07b49d738Adam Powell 13139a1de308cea2d160778fd977825f10a07b49d738Adam Powell void memberStatusChanged(RouteInfo info, CharSequence status) { 13149a1de308cea2d160778fd977825f10a07b49d738Adam Powell setStatusInt(status); 13159a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 13169a1de308cea2d160778fd977825f10a07b49d738Adam Powell 1317f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell void memberVolumeChanged(RouteInfo info) { 1318f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell updateVolume(); 1319f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell } 1320f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell 1321f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell void updateVolume() { 1322f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell // A group always represents the highest component volume value. 1323f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell final int routeCount = getRouteCount(); 1324f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell int volume = 0; 1325f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell for (int i = 0; i < routeCount; i++) { 1326f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell final int routeVol = getRouteAt(i).getVolume(); 1327f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell if (routeVol > volume) { 1328f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell volume = routeVol; 1329f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell } 1330f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell } 1331f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell if (volume != mVolume) { 1332f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell mVolume = volume; 1333f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell dispatchRouteVolumeChanged(this); 1334f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell } 1335f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell } 1336f8ac14a7f5a59b4ec8e89283a2da40b626e42065Adam Powell 1337d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell @Override 1338d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell void routeUpdated() { 1339d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell int types = 0; 1340d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell final int count = mRoutes.size(); 1341b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell if (count == 0) { 1342b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell // Don't keep empty groups in the router. 1343b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell MediaRouter.removeRoute(this); 1344b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell return; 1345b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell } 1346b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell 13478e37a85bf3dc39519942698dc90a3951306b934bAdam Powell int maxVolume = 0; 13488e37a85bf3dc39519942698dc90a3951306b934bAdam Powell boolean isLocal = true; 13498e37a85bf3dc39519942698dc90a3951306b934bAdam Powell boolean isFixedVolume = true; 1350d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell for (int i = 0; i < count; i++) { 13518e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final RouteInfo route = mRoutes.get(i); 13528e37a85bf3dc39519942698dc90a3951306b934bAdam Powell types |= route.mSupportedTypes; 13538e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final int routeMaxVolume = route.getVolumeMax(); 13548e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (routeMaxVolume > maxVolume) { 13558e37a85bf3dc39519942698dc90a3951306b934bAdam Powell maxVolume = routeMaxVolume; 13568e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 13578e37a85bf3dc39519942698dc90a3951306b934bAdam Powell isLocal &= route.getPlaybackType() == PLAYBACK_TYPE_LOCAL; 13588e37a85bf3dc39519942698dc90a3951306b934bAdam Powell isFixedVolume &= route.getVolumeHandling() == PLAYBACK_VOLUME_FIXED; 1359d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell } 13608e37a85bf3dc39519942698dc90a3951306b934bAdam Powell mPlaybackType = isLocal ? PLAYBACK_TYPE_LOCAL : PLAYBACK_TYPE_REMOTE; 13618e37a85bf3dc39519942698dc90a3951306b934bAdam Powell mVolumeHandling = isFixedVolume ? PLAYBACK_VOLUME_FIXED : PLAYBACK_VOLUME_VARIABLE; 1362d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell mSupportedTypes = types; 13638e37a85bf3dc39519942698dc90a3951306b934bAdam Powell mVolumeMax = maxVolume; 1364d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell mIcon = count == 1 ? mRoutes.get(0).getIconDrawable() : null; 1365d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell super.routeUpdated(); 1366d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell } 1367d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell 13689a1de308cea2d160778fd977825f10a07b49d738Adam Powell void updateName() { 13699a1de308cea2d160778fd977825f10a07b49d738Adam Powell final StringBuilder sb = new StringBuilder(); 13709a1de308cea2d160778fd977825f10a07b49d738Adam Powell final int count = mRoutes.size(); 13719a1de308cea2d160778fd977825f10a07b49d738Adam Powell for (int i = 0; i < count; i++) { 13729a1de308cea2d160778fd977825f10a07b49d738Adam Powell final RouteInfo info = mRoutes.get(i); 1373b5e2af5919351486a385effe77409d2a91ae9c19Adam Powell // TODO: There's probably a much more correct way to localize this. 13749a1de308cea2d160778fd977825f10a07b49d738Adam Powell if (i > 0) sb.append(", "); 13759a1de308cea2d160778fd977825f10a07b49d738Adam Powell sb.append(info.mName); 13769a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 13779a1de308cea2d160778fd977825f10a07b49d738Adam Powell mName = sb.toString(); 13789a1de308cea2d160778fd977825f10a07b49d738Adam Powell mUpdateName = false; 13799a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 1380d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell 1381d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell @Override 1382d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell public String toString() { 1383d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell StringBuilder sb = new StringBuilder(super.toString()); 1384d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell sb.append('['); 1385d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell final int count = mRoutes.size(); 1386d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell for (int i = 0; i < count; i++) { 1387d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell if (i > 0) sb.append(", "); 1388d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell sb.append(mRoutes.get(i)); 1389d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell } 1390d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell sb.append(']'); 1391d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell return sb.toString(); 1392d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell } 13939a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 13949a1de308cea2d160778fd977825f10a07b49d738Adam Powell 13959a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 13969a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Definition of a category of routes. All routes belong to a category. 13979a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 1398b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn public static class RouteCategory { 13999a1de308cea2d160778fd977825f10a07b49d738Adam Powell CharSequence mName; 14000d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell int mNameResId; 14019a1de308cea2d160778fd977825f10a07b49d738Adam Powell int mTypes; 14029a1de308cea2d160778fd977825f10a07b49d738Adam Powell final boolean mGroupable; 14039a1de308cea2d160778fd977825f10a07b49d738Adam Powell 14049a1de308cea2d160778fd977825f10a07b49d738Adam Powell RouteCategory(CharSequence name, int types, boolean groupable) { 14059a1de308cea2d160778fd977825f10a07b49d738Adam Powell mName = name; 14069a1de308cea2d160778fd977825f10a07b49d738Adam Powell mTypes = types; 14079a1de308cea2d160778fd977825f10a07b49d738Adam Powell mGroupable = groupable; 14089a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 14099a1de308cea2d160778fd977825f10a07b49d738Adam Powell 14100d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell RouteCategory(int nameResId, int types, boolean groupable) { 14110d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell mNameResId = nameResId; 14120d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell mTypes = types; 14130d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell mGroupable = groupable; 14140d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell } 14150d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell 14169a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 14179a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @return the name of this route category 14189a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 14199a1de308cea2d160778fd977825f10a07b49d738Adam Powell public CharSequence getName() { 14200d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell return getName(sStatic.mResources); 14210d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell } 14220d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell 14230d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell /** 14240d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * Return the properly localized/configuration dependent name of this RouteCategory. 14250d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * 14260d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * @param context Context to resolve name resources 14270d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * @return the name of this route category 14280d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell */ 14290d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public CharSequence getName(Context context) { 14300d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell return getName(context.getResources()); 14310d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell } 14320d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell 14330d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell CharSequence getName(Resources res) { 14340d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell if (mNameResId != 0) { 14350d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell return res.getText(mNameResId); 14360d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell } 14379a1de308cea2d160778fd977825f10a07b49d738Adam Powell return mName; 14389a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 14399a1de308cea2d160778fd977825f10a07b49d738Adam Powell 14409a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 1441d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * Return the current list of routes in this category that have been added 1442d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * to the MediaRouter. 14439a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 1444d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * <p>This list will not include routes that are nested within RouteGroups. 1445d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * A RouteGroup is treated as a single route within its category.</p> 1446d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * 1447d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param out a List to fill with the routes in this category. If this parameter is 1448d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * non-null, it will be cleared, filled with the current routes with this 1449d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * category, and returned. If this parameter is null, a new List will be 1450d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * allocated to report the category's current routes. 1451d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @return A list with the routes in this category that have been added to the MediaRouter. 14529a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 1453d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell public List<RouteInfo> getRoutes(List<RouteInfo> out) { 1454d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell if (out == null) { 1455d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell out = new ArrayList<RouteInfo>(); 1456d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell } else { 1457d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell out.clear(); 1458d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell } 1459d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell 1460b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn final int count = getRouteCountStatic(); 1461d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell for (int i = 0; i < count; i++) { 1462b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn final RouteInfo route = getRouteAtStatic(i); 1463d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell if (route.mCategory == this) { 1464d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell out.add(route); 1465d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell } 1466d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell } 1467d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell return out; 14689a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 14699a1de308cea2d160778fd977825f10a07b49d738Adam Powell 14709a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 14719a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @return Flag set describing the route types supported by this category 14729a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 14739a1de308cea2d160778fd977825f10a07b49d738Adam Powell public int getSupportedTypes() { 14749a1de308cea2d160778fd977825f10a07b49d738Adam Powell return mTypes; 14759a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 14769a1de308cea2d160778fd977825f10a07b49d738Adam Powell 14779a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 14789a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Return whether or not this category supports grouping. 14799a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 14809a1de308cea2d160778fd977825f10a07b49d738Adam Powell * <p>If this method returns true, all routes obtained from this category 1481d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * via calls to {@link #getRouteAt(int)} will be {@link MediaRouter.RouteGroup}s.</p> 14829a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 14839a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @return true if this category supports 14849a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 14859a1de308cea2d160778fd977825f10a07b49d738Adam Powell public boolean isGroupable() { 14869a1de308cea2d160778fd977825f10a07b49d738Adam Powell return mGroupable; 14879a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 14889a1de308cea2d160778fd977825f10a07b49d738Adam Powell 14899a1de308cea2d160778fd977825f10a07b49d738Adam Powell public String toString() { 14909a1de308cea2d160778fd977825f10a07b49d738Adam Powell return "RouteCategory{ name=" + mName + " types=" + typesToString(mTypes) + 1491d6d0bddee363e0c7fe61f63bd9d9864a71d887d6Adam Powell " groupable=" + mGroupable + " }"; 14929a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 14939a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 14949a1de308cea2d160778fd977825f10a07b49d738Adam Powell 14959a1de308cea2d160778fd977825f10a07b49d738Adam Powell static class CallbackInfo { 14969a1de308cea2d160778fd977825f10a07b49d738Adam Powell public int type; 1497b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn public final Callback cb; 1498b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn public final MediaRouter router; 14999a1de308cea2d160778fd977825f10a07b49d738Adam Powell 1500b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn public CallbackInfo(Callback cb, int type, MediaRouter router) { 15019a1de308cea2d160778fd977825f10a07b49d738Adam Powell this.cb = cb; 15029a1de308cea2d160778fd977825f10a07b49d738Adam Powell this.type = type; 1503b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn this.router = router; 15049a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 15059a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 15069a1de308cea2d160778fd977825f10a07b49d738Adam Powell 15079a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 15089a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Interface for receiving events about media routing changes. 15099a1de308cea2d160778fd977825f10a07b49d738Adam Powell * All methods of this interface will be called from the application's main thread. 15109a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 15119a1de308cea2d160778fd977825f10a07b49d738Adam Powell * <p>A Callback will only receive events relevant to routes that the callback 15129a1de308cea2d160778fd977825f10a07b49d738Adam Powell * was registered for.</p> 15139a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 15149a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @see MediaRouter#addCallback(int, Callback) 15159a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @see MediaRouter#removeCallback(Callback) 15169a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 15170d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public static abstract class Callback { 15189a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 15199a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Called when the supplied route becomes selected as the active route 15209a1de308cea2d160778fd977825f10a07b49d738Adam Powell * for the given route type. 15219a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 1522d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param router the MediaRouter reporting the event 15239a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param type Type flag set indicating the routes that have been selected 15249a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param info Route that has been selected for the given route types 15259a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 15260d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public abstract void onRouteSelected(MediaRouter router, int type, RouteInfo info); 15279a1de308cea2d160778fd977825f10a07b49d738Adam Powell 15289a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 15299a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Called when the supplied route becomes unselected as the active route 15309a1de308cea2d160778fd977825f10a07b49d738Adam Powell * for the given route type. 15319a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 1532d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param router the MediaRouter reporting the event 15339a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param type Type flag set indicating the routes that have been unselected 15349a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param info Route that has been unselected for the given route types 15359a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 15360d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public abstract void onRouteUnselected(MediaRouter router, int type, RouteInfo info); 15379a1de308cea2d160778fd977825f10a07b49d738Adam Powell 15389a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 15399a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Called when a route for the specified type was added. 15409a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 1541d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param router the MediaRouter reporting the event 15429a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param info Route that has become available for use 15439a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 15440d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public abstract void onRouteAdded(MediaRouter router, RouteInfo info); 15459a1de308cea2d160778fd977825f10a07b49d738Adam Powell 15469a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 15479a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Called when a route for the specified type was removed. 15489a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 1549d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param router the MediaRouter reporting the event 15509a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param info Route that has been removed from availability 15519a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 15520d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public abstract void onRouteRemoved(MediaRouter router, RouteInfo info); 15539a1de308cea2d160778fd977825f10a07b49d738Adam Powell 15549a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 15559a1de308cea2d160778fd977825f10a07b49d738Adam Powell * Called when an aspect of the indicated route has changed. 15569a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 15579a1de308cea2d160778fd977825f10a07b49d738Adam Powell * <p>This will not indicate that the types supported by this route have 15589a1de308cea2d160778fd977825f10a07b49d738Adam Powell * changed, only that cosmetic info such as name or status have been updated.</p> 15599a1de308cea2d160778fd977825f10a07b49d738Adam Powell * 1560d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param router the MediaRouter reporting the event 15619a1de308cea2d160778fd977825f10a07b49d738Adam Powell * @param info The route that was changed 15629a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 15630d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public abstract void onRouteChanged(MediaRouter router, RouteInfo info); 1564d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell 1565d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell /** 1566d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * Called when a route is added to a group. 1567d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * 1568d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param router the MediaRouter reporting the event 1569d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param info The route that was added 1570d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param group The group the route was added to 1571d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param index The route index within group that info was added at 1572d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell */ 15730d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public abstract void onRouteGrouped(MediaRouter router, RouteInfo info, RouteGroup group, 15740d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell int index); 1575d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell 1576d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell /** 1577d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * Called when a route is removed from a group. 1578d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * 1579d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param router the MediaRouter reporting the event 1580d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param info The route that was removed 1581d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell * @param group The group the route was removed from 1582d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell */ 15830d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public abstract void onRouteUngrouped(MediaRouter router, RouteInfo info, RouteGroup group); 15848e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 15858e37a85bf3dc39519942698dc90a3951306b934bAdam Powell /** 15868e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * Called when a route's volume changes. 15878e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * 15888e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * @param router the MediaRouter reporting the event 15898e37a85bf3dc39519942698dc90a3951306b934bAdam Powell * @param info The route with altered volume 15908e37a85bf3dc39519942698dc90a3951306b934bAdam Powell */ 15918e37a85bf3dc39519942698dc90a3951306b934bAdam Powell public abstract void onRouteVolumeChanged(MediaRouter router, RouteInfo info); 15929a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 15939a1de308cea2d160778fd977825f10a07b49d738Adam Powell 15949a1de308cea2d160778fd977825f10a07b49d738Adam Powell /** 15950d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * Stub implementation of {@link MediaRouter.Callback}. 15960d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell * Each abstract method is defined as a no-op. Override just the ones 15979a1de308cea2d160778fd977825f10a07b49d738Adam Powell * you need. 15989a1de308cea2d160778fd977825f10a07b49d738Adam Powell */ 15990d03c042f90bf62d5bad7c64e77028a5f9f8fae0Adam Powell public static class SimpleCallback extends Callback { 16009a1de308cea2d160778fd977825f10a07b49d738Adam Powell 16019a1de308cea2d160778fd977825f10a07b49d738Adam Powell @Override 1602d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell public void onRouteSelected(MediaRouter router, int type, RouteInfo info) { 16039a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 16049a1de308cea2d160778fd977825f10a07b49d738Adam Powell 16059a1de308cea2d160778fd977825f10a07b49d738Adam Powell @Override 1606d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell public void onRouteUnselected(MediaRouter router, int type, RouteInfo info) { 16079a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 16089a1de308cea2d160778fd977825f10a07b49d738Adam Powell 16099a1de308cea2d160778fd977825f10a07b49d738Adam Powell @Override 1610d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell public void onRouteAdded(MediaRouter router, RouteInfo info) { 16119a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 16129a1de308cea2d160778fd977825f10a07b49d738Adam Powell 16139a1de308cea2d160778fd977825f10a07b49d738Adam Powell @Override 1614d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell public void onRouteRemoved(MediaRouter router, RouteInfo info) { 16159a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 16169a1de308cea2d160778fd977825f10a07b49d738Adam Powell 16179a1de308cea2d160778fd977825f10a07b49d738Adam Powell @Override 1618d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell public void onRouteChanged(MediaRouter router, RouteInfo info) { 16199a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 16209a1de308cea2d160778fd977825f10a07b49d738Adam Powell 16219a1de308cea2d160778fd977825f10a07b49d738Adam Powell @Override 1622d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell public void onRouteGrouped(MediaRouter router, RouteInfo info, RouteGroup group, 1623d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell int index) { 16249a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 16259a1de308cea2d160778fd977825f10a07b49d738Adam Powell 16269a1de308cea2d160778fd977825f10a07b49d738Adam Powell @Override 1627d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell public void onRouteUngrouped(MediaRouter router, RouteInfo info, RouteGroup group) { 16289a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 1629d0d2cda9d414da73773285d7fee9e13aef3495e9Adam Powell 16308e37a85bf3dc39519942698dc90a3951306b934bAdam Powell @Override 16318e37a85bf3dc39519942698dc90a3951306b934bAdam Powell public void onRouteVolumeChanged(MediaRouter router, RouteInfo info) { 16328e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 16339a1de308cea2d160778fd977825f10a07b49d738Adam Powell } 16341357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 16351357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi static class VolumeCallbackInfo { 16361357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public final VolumeCallback vcb; 16371357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public final RouteInfo route; 16381357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 16391357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public VolumeCallbackInfo(VolumeCallback vcb, RouteInfo route) { 16401357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi this.vcb = vcb; 16411357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi this.route = route; 16421357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 16431357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 16441357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 16451357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 16461357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * Interface for receiving events about volume changes. 16471357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * All methods of this interface will be called from the application's main thread. 16481357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * 16491357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * <p>A VolumeCallback will only receive events relevant to routes that the callback 16501357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * was registered for.</p> 16511357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * 16521357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @see UserRouteInfo#setVolumeCallback(VolumeCallback) 16531357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 16541357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public static abstract class VolumeCallback { 16551357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 16561357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * Called when the volume for the route should be increased or decreased. 16571357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @param info the route affected by this event 16581357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @param direction an integer indicating whether the volume is to be increased 16591357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * (positive value) or decreased (negative value). 16601357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * For bundled changes, the absolute value indicates the number of changes 16611357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * in the same direction, e.g. +3 corresponds to three "volume up" changes. 16621357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 16631357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public abstract void onVolumeUpdateRequest(RouteInfo info, int direction); 16641357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi /** 16651357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * Called when the volume for the route should be set to the given value 16661357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @param info the route affected by this event 16671357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * @param volume an integer indicating the new volume value that should be used, always 16681357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi * between 0 and the value set by {@link UserRouteInfo#setVolumeMax(int)}. 16691357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi */ 16701357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public abstract void onVolumeSetRequest(RouteInfo info, int volume); 16711357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 16721357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 16738e37a85bf3dc39519942698dc90a3951306b934bAdam Powell static class VolumeChangeReceiver extends BroadcastReceiver { 16748e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 16758e37a85bf3dc39519942698dc90a3951306b934bAdam Powell @Override 16768e37a85bf3dc39519942698dc90a3951306b934bAdam Powell public void onReceive(Context context, Intent intent) { 16778e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (intent.getAction().equals(AudioManager.VOLUME_CHANGED_ACTION)) { 16788e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final int streamType = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, 16798e37a85bf3dc39519942698dc90a3951306b934bAdam Powell -1); 16808e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (streamType != AudioManager.STREAM_MUSIC) { 16818e37a85bf3dc39519942698dc90a3951306b934bAdam Powell return; 16828e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 16838e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 16848e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final int newVolume = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, 0); 16858e37a85bf3dc39519942698dc90a3951306b934bAdam Powell final int oldVolume = intent.getIntExtra( 16868e37a85bf3dc39519942698dc90a3951306b934bAdam Powell AudioManager.EXTRA_PREV_VOLUME_STREAM_VALUE, 0); 16878e37a85bf3dc39519942698dc90a3951306b934bAdam Powell if (newVolume != oldVolume) { 16888e37a85bf3dc39519942698dc90a3951306b934bAdam Powell systemVolumeChanged(newVolume); 16898e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 16908e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 16918e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 16928e37a85bf3dc39519942698dc90a3951306b934bAdam Powell 16938e37a85bf3dc39519942698dc90a3951306b934bAdam Powell } 16949a1de308cea2d160778fd977825f10a07b49d738Adam Powell} 1695