MediaRouter.java revision 9fcedc160282e6620f409ea46bf6728b35d011dd
1c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown/* 2c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Copyright (C) 2013 The Android Open Source Project 3c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 4c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Licensed under the Apache License, Version 2.0 (the "License"); 5c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * you may not use this file except in compliance with the License. 6c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * You may obtain a copy of the License at 7c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 8c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * http://www.apache.org/licenses/LICENSE-2.0 9c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 10c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Unless required by applicable law or agreed to in writing, software 11c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * distributed under the License is distributed on an "AS IS" BASIS, 12c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * See the License for the specific language governing permissions and 14c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * limitations under the License. 15c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 16c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 17b507e525a61ed761eecfc2eaaf19af7e8db5dca5Jeff Brownpackage android.support.v7.media; 18c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 19c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brownimport android.content.ContentResolver; 20c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brownimport android.content.Context; 21c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brownimport android.content.Intent; 22c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brownimport android.content.IntentFilter; 23fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brownimport android.content.pm.PackageManager.NameNotFoundException; 24fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brownimport android.content.res.Resources; 25c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brownimport android.os.Bundle; 26c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brownimport android.os.Handler; 27c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brownimport android.os.Looper; 28c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brownimport android.os.Message; 29c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brownimport android.support.v4.hardware.display.DisplayManagerCompat; 30b507e525a61ed761eecfc2eaaf19af7e8db5dca5Jeff Brownimport android.support.v7.media.MediaRouteProvider.ProviderMetadata; 31c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brownimport android.util.Log; 32c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brownimport android.view.Display; 33c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 349fcedc160282e6620f409ea46bf6728b35d011ddJeff Brownimport java.lang.ref.WeakReference; 35c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brownimport java.util.ArrayList; 36c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brownimport java.util.Collections; 37c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brownimport java.util.List; 38c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 39c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown/** 40c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * MediaRouter allows applications to control the routing of media channels 41c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * and streams from the current device to external speakers and destination devices. 42c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * <p> 43c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * A MediaRouter instance is retrieved through {@link #getInstance}. Applications 44c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * can query the media router about the currently selected route and its capabilities 45c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * to determine how to send content to the route's destination. Applications can 46c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * also {@link RouteInfo#sendControlRequest send control requests} to the route 47c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * to ask the route's destination to perform certain remote control functions 48fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * such as playing media. 49c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * </p><p> 50c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * See also {@link MediaRouteProvider} for information on how an application 51c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * can publish new media routes to the media router. 52c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * </p><p> 53c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * The media router API is not thread-safe; all interactions with it must be 54c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * done from the main thread of the process. 55c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * </p> 56c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 57c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brownpublic final class MediaRouter { 58c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown private static final String TAG = "MediaRouter"; 5911417b1cfde8f1749905f2d735623af9214148afJeff Brown private static final boolean DEBUG = false; 60c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 61c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown // Maintains global media router state for the process. 62c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown // This field is initialized in MediaRouter.getInstance() before any 63c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown // MediaRouter objects are instantiated so it is guaranteed to be 64c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown // valid whenever any instance method is invoked. 65c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown static GlobalMediaRouter sGlobal; 66c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 67c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown // Context-bound state of the media router. 68c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown final Context mContext; 699fcedc160282e6620f409ea46bf6728b35d011ddJeff Brown final ArrayList<CallbackRecord> mCallbackRecords = new ArrayList<CallbackRecord>(); 7011417b1cfde8f1749905f2d735623af9214148afJeff Brown 7111417b1cfde8f1749905f2d735623af9214148afJeff Brown /** 7211417b1cfde8f1749905f2d735623af9214148afJeff Brown * Flag for {@link #addCallback}: Actively scan for routes while this callback 7311417b1cfde8f1749905f2d735623af9214148afJeff Brown * is registered. 7411417b1cfde8f1749905f2d735623af9214148afJeff Brown * <p> 7511417b1cfde8f1749905f2d735623af9214148afJeff Brown * When this flag is specified, the media router will actively scan for new 7611417b1cfde8f1749905f2d735623af9214148afJeff Brown * routes. Certain routes, such as wifi display routes, may not be discoverable 7711417b1cfde8f1749905f2d735623af9214148afJeff Brown * except when actively scanning. This flag is typically used when the route picker 7811417b1cfde8f1749905f2d735623af9214148afJeff Brown * dialog has been opened by the user to ensure that the route information is 7911417b1cfde8f1749905f2d735623af9214148afJeff Brown * up to date. 8011417b1cfde8f1749905f2d735623af9214148afJeff Brown * </p><p> 8111417b1cfde8f1749905f2d735623af9214148afJeff Brown * Active scanning may consume a significant amount of power and may have intrusive 8211417b1cfde8f1749905f2d735623af9214148afJeff Brown * effects on wireless connectivity. Therefore it is important that active scanning 8311417b1cfde8f1749905f2d735623af9214148afJeff Brown * only be requested when it is actually needed to satisfy a user request to 8411417b1cfde8f1749905f2d735623af9214148afJeff Brown * discover and select a new route. 8511417b1cfde8f1749905f2d735623af9214148afJeff Brown * </p> 8611417b1cfde8f1749905f2d735623af9214148afJeff Brown */ 8711417b1cfde8f1749905f2d735623af9214148afJeff Brown public static final int CALLBACK_FLAG_ACTIVE_SCAN = 1 << 0; 8811417b1cfde8f1749905f2d735623af9214148afJeff Brown 8911417b1cfde8f1749905f2d735623af9214148afJeff Brown /** 9011417b1cfde8f1749905f2d735623af9214148afJeff Brown * Flag for {@link #addCallback}: Do not filter route events. 9111417b1cfde8f1749905f2d735623af9214148afJeff Brown * <p> 9211417b1cfde8f1749905f2d735623af9214148afJeff Brown * When this flag is specified, the callback will be invoked for events that affect any 9311417b1cfde8f1749905f2d735623af9214148afJeff Brown * route event if they do not match the callback's associated media route selector. 9411417b1cfde8f1749905f2d735623af9214148afJeff Brown * </p> 9511417b1cfde8f1749905f2d735623af9214148afJeff Brown */ 9611417b1cfde8f1749905f2d735623af9214148afJeff Brown public static final int CALLBACK_FLAG_UNFILTERED_EVENTS = 1 << 1; 9711417b1cfde8f1749905f2d735623af9214148afJeff Brown 9811417b1cfde8f1749905f2d735623af9214148afJeff Brown /** 9911417b1cfde8f1749905f2d735623af9214148afJeff Brown * Flag for {@link #isRouteAvailable}: Ignore the default route. 10011417b1cfde8f1749905f2d735623af9214148afJeff Brown * <p> 10111417b1cfde8f1749905f2d735623af9214148afJeff Brown * This flag is used to determine whether a matching non-default route is available. 10211417b1cfde8f1749905f2d735623af9214148afJeff Brown * This constraint may be used to decide whether to offer the route chooser dialog 10311417b1cfde8f1749905f2d735623af9214148afJeff Brown * to the user. There is no point offering the chooser if there are no 10411417b1cfde8f1749905f2d735623af9214148afJeff Brown * non-default choices. 10511417b1cfde8f1749905f2d735623af9214148afJeff Brown * </p> 10611417b1cfde8f1749905f2d735623af9214148afJeff Brown */ 10711417b1cfde8f1749905f2d735623af9214148afJeff Brown public static final int AVAILABILITY_FLAG_IGNORE_DEFAULT_ROUTE = 1 << 0; 10811417b1cfde8f1749905f2d735623af9214148afJeff Brown 10911417b1cfde8f1749905f2d735623af9214148afJeff Brown /** 11011417b1cfde8f1749905f2d735623af9214148afJeff Brown * Flag for {@link #isRouteAvailable}: Consider whether matching routes 11111417b1cfde8f1749905f2d735623af9214148afJeff Brown * might be discovered if an active scan were performed. 11211417b1cfde8f1749905f2d735623af9214148afJeff Brown * <p> 11311417b1cfde8f1749905f2d735623af9214148afJeff Brown * If no existing routes match the route selector, then this flag is used to 1149942d40d0d952b03b583fe66f434676793697aa2Jeff Brown * determine whether route providers that require active scans might discover 1159942d40d0d952b03b583fe66f434676793697aa2Jeff Brown * matching routes if an active scan were actually performed. 11611417b1cfde8f1749905f2d735623af9214148afJeff Brown * </p><p> 11711417b1cfde8f1749905f2d735623af9214148afJeff Brown * This flag may be used to decide whether to offer the route chooser dialog to the user. 1189942d40d0d952b03b583fe66f434676793697aa2Jeff Brown * When the dialog is opened, route providers are provided an opportunity 1199942d40d0d952b03b583fe66f434676793697aa2Jeff Brown * to perform active scans to discover additional routes. 12011417b1cfde8f1749905f2d735623af9214148afJeff Brown * </p> 1219942d40d0d952b03b583fe66f434676793697aa2Jeff Brown * 1229942d40d0d952b03b583fe66f434676793697aa2Jeff Brown * @see #CALLBACK_FLAG_ACTIVE_SCAN 12311417b1cfde8f1749905f2d735623af9214148afJeff Brown */ 12411417b1cfde8f1749905f2d735623af9214148afJeff Brown public static final int AVAILABILITY_FLAG_CONSIDER_ACTIVE_SCAN = 1 << 1; 125c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 126c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown MediaRouter(Context context) { 127c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown mContext = context; 128c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 129c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 130c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 1319fcedc160282e6620f409ea46bf6728b35d011ddJeff Brown * Gets an instance of the media router service associated with the context. 1329fcedc160282e6620f409ea46bf6728b35d011ddJeff Brown * <p> 1339fcedc160282e6620f409ea46bf6728b35d011ddJeff Brown * The application is responsible for holding a strong reference to the returned 1349fcedc160282e6620f409ea46bf6728b35d011ddJeff Brown * {@link MediaRouter} instance, such as by storing the instance in a field of 1359fcedc160282e6620f409ea46bf6728b35d011ddJeff Brown * the {@link android.app.Activity}, to ensure that the media router remains alive 1369fcedc160282e6620f409ea46bf6728b35d011ddJeff Brown * as long as the application is using its features. 1379fcedc160282e6620f409ea46bf6728b35d011ddJeff Brown * </p><p> 1389fcedc160282e6620f409ea46bf6728b35d011ddJeff Brown * In other words, the support library only holds a {@link WeakReference weak reference} 1399fcedc160282e6620f409ea46bf6728b35d011ddJeff Brown * to each media router instance. When there are no remaining strong references to the 1409fcedc160282e6620f409ea46bf6728b35d011ddJeff Brown * media router instance, all of its callbacks will be removed and route discovery 1419fcedc160282e6620f409ea46bf6728b35d011ddJeff Brown * will no longer be performed on its behalf. 1429fcedc160282e6620f409ea46bf6728b35d011ddJeff Brown * </p> 1439fcedc160282e6620f409ea46bf6728b35d011ddJeff Brown * 1449fcedc160282e6620f409ea46bf6728b35d011ddJeff Brown * @return The media router instance for the context. The application must hold 1459fcedc160282e6620f409ea46bf6728b35d011ddJeff Brown * a strong reference to this object as long as it is in use. 146c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 147c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public static MediaRouter getInstance(Context context) { 148c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (context == null) { 149c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown throw new IllegalArgumentException("context must not be null"); 150c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 151c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown checkCallingThread(); 152c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 153c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (sGlobal == null) { 154c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown sGlobal = new GlobalMediaRouter(context.getApplicationContext()); 155fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown sGlobal.start(); 156c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 157c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return sGlobal.getRouter(context); 158c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 159c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 160c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 161fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * Gets information about the {@link MediaRouter.RouteInfo routes} currently known to 162fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * this media router. 163c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 164c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public List<RouteInfo> getRoutes() { 165c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown checkCallingThread(); 166c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return sGlobal.getRoutes(); 167c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 168c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 169c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 170fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * Gets information about the {@link MediaRouter.ProviderInfo route providers} 171fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * currently known to this media router. 172fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown */ 173fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public List<ProviderInfo> getProviders() { 174fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown checkCallingThread(); 175fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return sGlobal.getProviders(); 176fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 177fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 178fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown /** 179c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Gets the default route for playing media content on the system. 180c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * <p> 181c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * The system always provides a default route. 182c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * </p> 183c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 184c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @return The default route, which is guaranteed to never be null. 185c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 186c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public RouteInfo getDefaultRoute() { 187c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown checkCallingThread(); 188c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return sGlobal.getDefaultRoute(); 189c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 190c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 191c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 192c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Gets the currently selected route. 193c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * <p> 194c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * The application should examine the route's 195fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * {@link RouteInfo#getControlFilters media control intent filters} to assess the 196c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * capabilities of the route before attempting to use it. 197c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * </p> 198c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 199c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * <h3>Example</h3> 200c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * <pre> 201c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * public boolean playMovie() { 202c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * MediaRouter mediaRouter = MediaRouter.getInstance(context); 203c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * MediaRouter.RouteInfo route = mediaRouter.getSelectedRoute(); 204c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 205c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * // First try using the remote playback interface, if supported. 206c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * if (route.supportsControlCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK)) { 207c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * // The route supports remote playback. 208c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * // Try to send it the Uri of the movie to play. 209c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Intent intent = new Intent(MediaControlIntent.ACTION_PLAY); 210c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * intent.addCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK); 211c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * intent.setDataAndType("http://example.com/videos/movie.mp4", "video/mp4"); 212fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * if (route.supportsControlRequest(intent)) { 213fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * route.sendControlRequest(intent, null); 214fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * return true; // sent the request to play the movie 215c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * } 216c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * } 217c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 218c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * // If remote playback was not possible, then play locally. 219c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * if (route.supportsControlCategory(MediaControlIntent.CATEGORY_LIVE_VIDEO)) { 220c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * // The route supports live video streaming. 221c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * // Prepare to play content locally in a window or in a presentation. 222c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * return playMovieInWindow(); 223c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * } 224c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 225c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * // Neither interface is supported, so we can't play the movie to this route. 226c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * return false; 227c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * } 228c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * </pre> 229c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 230c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @return The selected route, which is guaranteed to never be null. 231c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 232fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * @see RouteInfo#getControlFilters 233c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @see RouteInfo#supportsControlCategory 234c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @see RouteInfo#supportsControlRequest 235c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 236c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public RouteInfo getSelectedRoute() { 237c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown checkCallingThread(); 238c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return sGlobal.getSelectedRoute(); 239c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 240c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 241c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 24228520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown * Returns the selected route if it matches the specified selector, otherwise 24328520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown * selects the default route and returns it. 24428520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown * 24528520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown * @param selector The selector to match. 24628520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown * @return The previously selected route if it matched the selector, otherwise the 24728520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown * newly selected default route which is guaranteed to never be null. 24828520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown * 24911417b1cfde8f1749905f2d735623af9214148afJeff Brown * @see MediaRouteSelector 25028520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown * @see RouteInfo#matchesSelector 25128520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown * @see RouteInfo#isDefault 25228520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown */ 25311417b1cfde8f1749905f2d735623af9214148afJeff Brown public RouteInfo updateSelectedRoute(MediaRouteSelector selector) { 25428520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown if (selector == null) { 25528520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown throw new IllegalArgumentException("selector must not be null"); 25628520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown } 25728520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown checkCallingThread(); 25828520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown 25911417b1cfde8f1749905f2d735623af9214148afJeff Brown if (DEBUG) { 26011417b1cfde8f1749905f2d735623af9214148afJeff Brown Log.d(TAG, "updateSelectedRoute: " + selector); 26111417b1cfde8f1749905f2d735623af9214148afJeff Brown } 26228520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown RouteInfo route = sGlobal.getSelectedRoute(); 26311417b1cfde8f1749905f2d735623af9214148afJeff Brown if (!route.isDefault() && !route.matchesSelector(selector)) { 26428520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown route = sGlobal.getDefaultRoute(); 26528520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown sGlobal.selectRoute(route); 26628520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown } 26728520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown return route; 26828520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown } 26928520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown 27028520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown /** 271c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Selects the specified route. 272c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 273c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @param route The route to select. 274c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 275c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public void selectRoute(RouteInfo route) { 276c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (route == null) { 277c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown throw new IllegalArgumentException("route must not be null"); 278c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 279c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown checkCallingThread(); 280c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 28111417b1cfde8f1749905f2d735623af9214148afJeff Brown if (DEBUG) { 28211417b1cfde8f1749905f2d735623af9214148afJeff Brown Log.d(TAG, "selectRoute: " + route); 28311417b1cfde8f1749905f2d735623af9214148afJeff Brown } 284c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown sGlobal.selectRoute(route); 285c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 286c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 287c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 28811417b1cfde8f1749905f2d735623af9214148afJeff Brown * Returns true if there is a route that matches the specified selector 28911417b1cfde8f1749905f2d735623af9214148afJeff Brown * or, depending on the specified availability flags, if it is possible to discover one. 29011417b1cfde8f1749905f2d735623af9214148afJeff Brown * <p> 29111417b1cfde8f1749905f2d735623af9214148afJeff Brown * This method first considers whether there are any available 29211417b1cfde8f1749905f2d735623af9214148afJeff Brown * routes that match the selector regardless of whether they are enabled or 29311417b1cfde8f1749905f2d735623af9214148afJeff Brown * disabled. If not and the {@link #AVAILABILITY_FLAG_CONSIDER_ACTIVE_SCAN} flag 29411417b1cfde8f1749905f2d735623af9214148afJeff Brown * was specifies, then it considers whether any of the route providers 29511417b1cfde8f1749905f2d735623af9214148afJeff Brown * could discover a matching route if an active scan were performed. 29611417b1cfde8f1749905f2d735623af9214148afJeff Brown * </p> 297c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 29811417b1cfde8f1749905f2d735623af9214148afJeff Brown * @param selector The selector to match. 29911417b1cfde8f1749905f2d735623af9214148afJeff Brown * @param flags Flags to control the determination of whether a route may be available. 30011417b1cfde8f1749905f2d735623af9214148afJeff Brown * May be zero or a combination of 30111417b1cfde8f1749905f2d735623af9214148afJeff Brown * {@link #AVAILABILITY_FLAG_IGNORE_DEFAULT_ROUTE} and 30211417b1cfde8f1749905f2d735623af9214148afJeff Brown * {@link #AVAILABILITY_FLAG_CONSIDER_ACTIVE_SCAN}. 30311417b1cfde8f1749905f2d735623af9214148afJeff Brown * @return True if a matching route may be available. 304c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 30511417b1cfde8f1749905f2d735623af9214148afJeff Brown public boolean isRouteAvailable(MediaRouteSelector selector, int flags) { 30611417b1cfde8f1749905f2d735623af9214148afJeff Brown if (selector == null) { 30711417b1cfde8f1749905f2d735623af9214148afJeff Brown throw new IllegalArgumentException("selector must not be null"); 308c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 309c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown checkCallingThread(); 310c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 31111417b1cfde8f1749905f2d735623af9214148afJeff Brown return sGlobal.isRouteAvailable(selector, flags); 312c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 313c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 314c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 31511417b1cfde8f1749905f2d735623af9214148afJeff Brown * Registers a callback to discover routes that match the selector and to receive 31611417b1cfde8f1749905f2d735623af9214148afJeff Brown * events when they change. 31711417b1cfde8f1749905f2d735623af9214148afJeff Brown * <p> 31811417b1cfde8f1749905f2d735623af9214148afJeff Brown * This is a convenience method that has the same effect as calling 31911417b1cfde8f1749905f2d735623af9214148afJeff Brown * {@link #addCallback(MediaRouteSelector, Callback, int)} without flags. 32011417b1cfde8f1749905f2d735623af9214148afJeff Brown * </p> 321c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 32211417b1cfde8f1749905f2d735623af9214148afJeff Brown * @param selector A route selector that indicates the kinds of routes that the 32311417b1cfde8f1749905f2d735623af9214148afJeff Brown * callback would like to discover. 32411417b1cfde8f1749905f2d735623af9214148afJeff Brown * @param callback The callback to add. 32511417b1cfde8f1749905f2d735623af9214148afJeff Brown * @see #removeCallback 326c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 32711417b1cfde8f1749905f2d735623af9214148afJeff Brown public void addCallback(MediaRouteSelector selector, Callback callback) { 32811417b1cfde8f1749905f2d735623af9214148afJeff Brown addCallback(selector, callback, 0); 329c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 330c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 331c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 33211417b1cfde8f1749905f2d735623af9214148afJeff Brown * Registers a callback to discover routes that match the selector and to receive 33311417b1cfde8f1749905f2d735623af9214148afJeff Brown * events when they change. 33428520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown * <p> 33511417b1cfde8f1749905f2d735623af9214148afJeff Brown * The selector describes the kinds of routes that the application wants to 33611417b1cfde8f1749905f2d735623af9214148afJeff Brown * discover. For example, if the application wants to use 33711417b1cfde8f1749905f2d735623af9214148afJeff Brown * live audio routes then it should include the 33811417b1cfde8f1749905f2d735623af9214148afJeff Brown * {@link MediaControlIntent#CATEGORY_LIVE_AUDIO live audio media control intent category} 33911417b1cfde8f1749905f2d735623af9214148afJeff Brown * in its selector when it adds a callback to the media router. 34011417b1cfde8f1749905f2d735623af9214148afJeff Brown * The selector may include any number of categories. 34128520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown * </p><p> 34211417b1cfde8f1749905f2d735623af9214148afJeff Brown * If the callback has already been registered, then the selector is added to 34311417b1cfde8f1749905f2d735623af9214148afJeff Brown * the set of selectors being monitored by the callback. 34411417b1cfde8f1749905f2d735623af9214148afJeff Brown * </p><p> 34511417b1cfde8f1749905f2d735623af9214148afJeff Brown * By default, the callback will only be invoked for events that affect routes 34611417b1cfde8f1749905f2d735623af9214148afJeff Brown * that match the specified selector. Event filtering may be disabled by specifying 34711417b1cfde8f1749905f2d735623af9214148afJeff Brown * the {@link #CALLBACK_FLAG_UNFILTERED_EVENTS} flag when the callback is registered. 34828520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown * </p> 34928520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown * 35028520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown * <h3>Example</h3> 35128520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown * <pre> 35211417b1cfde8f1749905f2d735623af9214148afJeff Brown * public class MyActivity extends Activity { 35311417b1cfde8f1749905f2d735623af9214148afJeff Brown * private MediaRouter mRouter; 35411417b1cfde8f1749905f2d735623af9214148afJeff Brown * private MediaRouter.Callback mCallback; 35511417b1cfde8f1749905f2d735623af9214148afJeff Brown * private MediaRouteSelector mSelector; 35628520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown * 35711417b1cfde8f1749905f2d735623af9214148afJeff Brown * protected void onCreate(Bundle savedInstanceState) { 35811417b1cfde8f1749905f2d735623af9214148afJeff Brown * super.onCreate(savedInstanceState); 35911417b1cfde8f1749905f2d735623af9214148afJeff Brown * 36011417b1cfde8f1749905f2d735623af9214148afJeff Brown * mRouter = Mediarouter.getInstance(this); 36111417b1cfde8f1749905f2d735623af9214148afJeff Brown * mCallback = new MyCallback(); 36211417b1cfde8f1749905f2d735623af9214148afJeff Brown * mSelector = new MediaRouteSelector.Builder() 36311417b1cfde8f1749905f2d735623af9214148afJeff Brown * .addControlCategory(MediaControlIntent.CATEGORY_LIVE_AUDIO) 36411417b1cfde8f1749905f2d735623af9214148afJeff Brown * .addControlCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK) 36511417b1cfde8f1749905f2d735623af9214148afJeff Brown * .build(); 36628520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown * } 36728520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown * 36811417b1cfde8f1749905f2d735623af9214148afJeff Brown * // Add the callback on resume to tell the media router what kinds of routes 36911417b1cfde8f1749905f2d735623af9214148afJeff Brown * // the application is interested in so that it can try to discover suitable ones. 37011417b1cfde8f1749905f2d735623af9214148afJeff Brown * public void onResume() { 37111417b1cfde8f1749905f2d735623af9214148afJeff Brown * super.onResume(); 37211417b1cfde8f1749905f2d735623af9214148afJeff Brown * 37311417b1cfde8f1749905f2d735623af9214148afJeff Brown * mediaRouter.addCallback(mSelector, mCallback); 37411417b1cfde8f1749905f2d735623af9214148afJeff Brown * 37511417b1cfde8f1749905f2d735623af9214148afJeff Brown * MediaRouter.RouteInfo route = mediaRouter.updateSelectedRoute(mSelector); 37611417b1cfde8f1749905f2d735623af9214148afJeff Brown * // do something with the route... 37711417b1cfde8f1749905f2d735623af9214148afJeff Brown * } 37811417b1cfde8f1749905f2d735623af9214148afJeff Brown * 37911417b1cfde8f1749905f2d735623af9214148afJeff Brown * // Remove the selector on pause to tell the media router that it no longer 38011417b1cfde8f1749905f2d735623af9214148afJeff Brown * // needs to invest effort trying to discover routes of these kinds for now. 38111417b1cfde8f1749905f2d735623af9214148afJeff Brown * public void onPause() { 38211417b1cfde8f1749905f2d735623af9214148afJeff Brown * super.onPause(); 38311417b1cfde8f1749905f2d735623af9214148afJeff Brown * 38411417b1cfde8f1749905f2d735623af9214148afJeff Brown * mediaRouter.removeCallback(mCallback); 38511417b1cfde8f1749905f2d735623af9214148afJeff Brown * } 38611417b1cfde8f1749905f2d735623af9214148afJeff Brown * 38711417b1cfde8f1749905f2d735623af9214148afJeff Brown * private final class MyCallback extends MediaRouter.Callback { 38811417b1cfde8f1749905f2d735623af9214148afJeff Brown * // Implement callback methods as needed. 38928520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown * } 39028520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown * } 39128520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown * </pre> 39228520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown * 39311417b1cfde8f1749905f2d735623af9214148afJeff Brown * @param selector A route selector that indicates the kinds of routes that the 39411417b1cfde8f1749905f2d735623af9214148afJeff Brown * callback would like to discover. 39511417b1cfde8f1749905f2d735623af9214148afJeff Brown * @param callback The callback to add. 39611417b1cfde8f1749905f2d735623af9214148afJeff Brown * @param flags Flags to control the behavior of the callback. 39711417b1cfde8f1749905f2d735623af9214148afJeff Brown * May be zero or a combination of {@link #CALLBACK_FLAG_ACTIVE_SCAN} and 39811417b1cfde8f1749905f2d735623af9214148afJeff Brown * {@link #CALLBACK_FLAG_UNFILTERED_EVENTS}. 39911417b1cfde8f1749905f2d735623af9214148afJeff Brown * @see #removeCallback 40028520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown */ 40111417b1cfde8f1749905f2d735623af9214148afJeff Brown public void addCallback(MediaRouteSelector selector, Callback callback, int flags) { 40228520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown if (selector == null) { 40328520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown throw new IllegalArgumentException("selector must not be null"); 40428520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown } 40511417b1cfde8f1749905f2d735623af9214148afJeff Brown if (callback == null) { 40611417b1cfde8f1749905f2d735623af9214148afJeff Brown throw new IllegalArgumentException("callback must not be null"); 40711417b1cfde8f1749905f2d735623af9214148afJeff Brown } 40828520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown checkCallingThread(); 40928520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown 41011417b1cfde8f1749905f2d735623af9214148afJeff Brown if (DEBUG) { 41111417b1cfde8f1749905f2d735623af9214148afJeff Brown Log.d(TAG, "addCallback: selector=" + selector 41211417b1cfde8f1749905f2d735623af9214148afJeff Brown + ", callback=" + callback + ", flags=" + Integer.toHexString(flags)); 41311417b1cfde8f1749905f2d735623af9214148afJeff Brown } 41411417b1cfde8f1749905f2d735623af9214148afJeff Brown 41511417b1cfde8f1749905f2d735623af9214148afJeff Brown CallbackRecord record; 41611417b1cfde8f1749905f2d735623af9214148afJeff Brown int index = findCallbackRecord(callback); 41711417b1cfde8f1749905f2d735623af9214148afJeff Brown if (index < 0) { 4189fcedc160282e6620f409ea46bf6728b35d011ddJeff Brown record = new CallbackRecord(this, callback); 41911417b1cfde8f1749905f2d735623af9214148afJeff Brown mCallbackRecords.add(record); 42011417b1cfde8f1749905f2d735623af9214148afJeff Brown } else { 42111417b1cfde8f1749905f2d735623af9214148afJeff Brown record = mCallbackRecords.get(index); 42211417b1cfde8f1749905f2d735623af9214148afJeff Brown } 42311417b1cfde8f1749905f2d735623af9214148afJeff Brown boolean updateNeeded = false; 42411417b1cfde8f1749905f2d735623af9214148afJeff Brown if ((flags & ~record.mFlags) != 0) { 42511417b1cfde8f1749905f2d735623af9214148afJeff Brown record.mFlags |= flags; 42611417b1cfde8f1749905f2d735623af9214148afJeff Brown updateNeeded = true; 42711417b1cfde8f1749905f2d735623af9214148afJeff Brown } 42811417b1cfde8f1749905f2d735623af9214148afJeff Brown if (!record.mSelector.contains(selector)) { 42911417b1cfde8f1749905f2d735623af9214148afJeff Brown record.mSelector = new MediaRouteSelector.Builder(record.mSelector) 43011417b1cfde8f1749905f2d735623af9214148afJeff Brown .addSelector(selector) 43111417b1cfde8f1749905f2d735623af9214148afJeff Brown .build(); 43211417b1cfde8f1749905f2d735623af9214148afJeff Brown updateNeeded = true; 43311417b1cfde8f1749905f2d735623af9214148afJeff Brown } 43411417b1cfde8f1749905f2d735623af9214148afJeff Brown if (updateNeeded) { 43511417b1cfde8f1749905f2d735623af9214148afJeff Brown sGlobal.updateDiscoveryRequest(); 43628520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown } 43728520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown } 43828520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown 43928520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown /** 44011417b1cfde8f1749905f2d735623af9214148afJeff Brown * Removes the specified callback. It will no longer receive events about 44111417b1cfde8f1749905f2d735623af9214148afJeff Brown * changes to media routes. 44228520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown * 44311417b1cfde8f1749905f2d735623af9214148afJeff Brown * @param callback The callback to remove. 44411417b1cfde8f1749905f2d735623af9214148afJeff Brown * @see #addCallback 44528520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown */ 44611417b1cfde8f1749905f2d735623af9214148afJeff Brown public void removeCallback(Callback callback) { 44711417b1cfde8f1749905f2d735623af9214148afJeff Brown if (callback == null) { 44811417b1cfde8f1749905f2d735623af9214148afJeff Brown throw new IllegalArgumentException("callback must not be null"); 44928520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown } 45028520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown checkCallingThread(); 45128520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown 45211417b1cfde8f1749905f2d735623af9214148afJeff Brown if (DEBUG) { 45311417b1cfde8f1749905f2d735623af9214148afJeff Brown Log.d(TAG, "removeCallback: callback=" + callback); 45411417b1cfde8f1749905f2d735623af9214148afJeff Brown } 45511417b1cfde8f1749905f2d735623af9214148afJeff Brown 45611417b1cfde8f1749905f2d735623af9214148afJeff Brown int index = findCallbackRecord(callback); 45711417b1cfde8f1749905f2d735623af9214148afJeff Brown if (index >= 0) { 45811417b1cfde8f1749905f2d735623af9214148afJeff Brown mCallbackRecords.remove(index); 45911417b1cfde8f1749905f2d735623af9214148afJeff Brown sGlobal.updateDiscoveryRequest(); 46028520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown } 46128520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown } 46228520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown 46311417b1cfde8f1749905f2d735623af9214148afJeff Brown private int findCallbackRecord(Callback callback) { 46411417b1cfde8f1749905f2d735623af9214148afJeff Brown final int count = mCallbackRecords.size(); 46511417b1cfde8f1749905f2d735623af9214148afJeff Brown for (int i = 0; i < count; i++) { 46611417b1cfde8f1749905f2d735623af9214148afJeff Brown if (mCallbackRecords.get(i).mCallback == callback) { 46711417b1cfde8f1749905f2d735623af9214148afJeff Brown return i; 46811417b1cfde8f1749905f2d735623af9214148afJeff Brown } 46911417b1cfde8f1749905f2d735623af9214148afJeff Brown } 47011417b1cfde8f1749905f2d735623af9214148afJeff Brown return -1; 47111417b1cfde8f1749905f2d735623af9214148afJeff Brown } 47211417b1cfde8f1749905f2d735623af9214148afJeff Brown 47328520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown /** 4749942d40d0d952b03b583fe66f434676793697aa2Jeff Brown * Registers a media route provider within this application process. 4759942d40d0d952b03b583fe66f434676793697aa2Jeff Brown * <p> 4769942d40d0d952b03b583fe66f434676793697aa2Jeff Brown * The provider will be added to the list of providers that all {@link MediaRouter} 4779942d40d0d952b03b583fe66f434676793697aa2Jeff Brown * instances within this process can use to discover routes. 4789942d40d0d952b03b583fe66f434676793697aa2Jeff Brown * </p> 479c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 480fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * @param providerInstance The media route provider instance to add. 481c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 482c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @see MediaRouteProvider 48328520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown * @see #removeCallback 484c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 485fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public void addProvider(MediaRouteProvider providerInstance) { 486fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (providerInstance == null) { 487fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown throw new IllegalArgumentException("providerInstance must not be null"); 488c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 489c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown checkCallingThread(); 490c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 49111417b1cfde8f1749905f2d735623af9214148afJeff Brown if (DEBUG) { 49211417b1cfde8f1749905f2d735623af9214148afJeff Brown Log.d(TAG, "addProvider: " + providerInstance); 49311417b1cfde8f1749905f2d735623af9214148afJeff Brown } 494fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown sGlobal.addProvider(providerInstance); 495c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 496c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 497c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 4989942d40d0d952b03b583fe66f434676793697aa2Jeff Brown * Unregisters a media route provider within this application process. 4999942d40d0d952b03b583fe66f434676793697aa2Jeff Brown * <p> 5009942d40d0d952b03b583fe66f434676793697aa2Jeff Brown * The provider will be removed from the list of providers that all {@link MediaRouter} 5019942d40d0d952b03b583fe66f434676793697aa2Jeff Brown * instances within this process can use to discover routes. 5029942d40d0d952b03b583fe66f434676793697aa2Jeff Brown * </p> 503c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 504fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * @param providerInstance The media route provider instance to remove. 505c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 506c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @see MediaRouteProvider 50728520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown * @see #addCallback 508c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 509fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public void removeProvider(MediaRouteProvider providerInstance) { 510fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (providerInstance == null) { 511fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown throw new IllegalArgumentException("providerInstance must not be null"); 512c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 513c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown checkCallingThread(); 514c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 51511417b1cfde8f1749905f2d735623af9214148afJeff Brown if (DEBUG) { 51611417b1cfde8f1749905f2d735623af9214148afJeff Brown Log.d(TAG, "removeProvider: " + providerInstance); 51728520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown } 51811417b1cfde8f1749905f2d735623af9214148afJeff Brown sGlobal.removeProvider(providerInstance); 51928520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown } 52028520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown 52128520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown /** 522c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Ensures that calls into the media router are on the correct thread. 523c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * It pays to be a little paranoid when global state invariants are at risk. 524c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 525c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown static void checkCallingThread() { 526c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (Looper.myLooper() != Looper.getMainLooper()) { 527c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown throw new IllegalStateException("The media router service must only be " 528c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown + "accessed on the application's main thread."); 529c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 530c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 531c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 532c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown static <T> boolean equal(T a, T b) { 533c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return a == b || (a != null && b != null && a.equals(b)); 534c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 535c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 536c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 537c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Provides information about a media route. 538c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * <p> 539fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * Each media route has a list of {@link MediaControlIntent media control} 540fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * {@link #getControlFilters intent filters} that describe the capabilities of the 541c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * route and the manner in which it is used and controlled. 542c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * </p> 543c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 544c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public static final class RouteInfo { 545fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private final ProviderInfo mProvider; 546c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown private final String mDescriptorId; 547c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown private String mName; 548d63957d28aaabcec588b8cde12eac16414783aebJeff Brown private String mDescription; 549c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown private boolean mEnabled; 55011417b1cfde8f1749905f2d735623af9214148afJeff Brown private boolean mConnecting; 551fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private final ArrayList<IntentFilter> mControlFilters = new ArrayList<IntentFilter>(); 552c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown private int mPlaybackType; 553c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown private int mPlaybackStream; 554c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown private int mVolumeHandling; 555c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown private int mVolume; 556c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown private int mVolumeMax; 557c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown private Display mPresentationDisplay; 558c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown private int mPresentationDisplayId = -1; 559c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown private Bundle mExtras; 56011417b1cfde8f1749905f2d735623af9214148afJeff Brown private MediaRouteDescriptor mDescriptor; 561c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 562c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 563c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * The default playback type, "local", indicating the presentation of the media 564c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * is happening on the same device (e.g. a phone, a tablet) as where it is 565c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * controlled from. 566c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 567c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @see #getPlaybackType 568c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 569c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public static final int PLAYBACK_TYPE_LOCAL = 0; 570c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 571c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 572c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * A playback type indicating the presentation of the media is happening on 573c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * a different device (i.e. the remote device) than where it is controlled from. 574c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 575c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @see #getPlaybackType 576c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 577c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public static final int PLAYBACK_TYPE_REMOTE = 1; 578c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 579c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 580c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Playback information indicating the playback volume is fixed, i.e. it cannot be 581c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * controlled from this object. An example of fixed playback volume is a remote player, 582c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * playing over HDMI where the user prefers to control the volume on the HDMI sink, rather 583c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * than attenuate at the source. 584c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 585c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @see #getVolumeHandling 586c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 587c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public static final int PLAYBACK_VOLUME_FIXED = 0; 588c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 589c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 590c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Playback information indicating the playback volume is variable and can be controlled 591c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * from this object. 592c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 593c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @see #getVolumeHandling 594c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 595c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public static final int PLAYBACK_VOLUME_VARIABLE = 1; 596c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 597c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown static final int CHANGE_GENERAL = 1 << 0; 598c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown static final int CHANGE_VOLUME = 1 << 1; 599c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown static final int CHANGE_PRESENTATION_DISPLAY = 1 << 2; 600c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 601fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown RouteInfo(ProviderInfo provider, String descriptorId) { 602fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mProvider = provider; 603c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown mDescriptorId = descriptorId; 604c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 605c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 606fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown /** 607fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * Gets information about the provider of this media route. 608fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown */ 609fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public ProviderInfo getProvider() { 610fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return mProvider; 611c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 612c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 613c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 614d63957d28aaabcec588b8cde12eac16414783aebJeff Brown * Gets the user-visible name of the route. 615d63957d28aaabcec588b8cde12eac16414783aebJeff Brown * <p> 616d63957d28aaabcec588b8cde12eac16414783aebJeff Brown * The route name identifies the destination represented by the route. 617d63957d28aaabcec588b8cde12eac16414783aebJeff Brown * It may be a user-supplied name, an alias, or device serial number. 618d63957d28aaabcec588b8cde12eac16414783aebJeff Brown * </p> 619c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 620d63957d28aaabcec588b8cde12eac16414783aebJeff Brown * @return The user-visible name of a media route. This is the string presented 621c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * to users who may select this as the active route. 622c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 623c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public String getName() { 624c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return mName; 625c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 626c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 627c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 628d63957d28aaabcec588b8cde12eac16414783aebJeff Brown * Gets the user-visible description of the route. 629d63957d28aaabcec588b8cde12eac16414783aebJeff Brown * <p> 630d63957d28aaabcec588b8cde12eac16414783aebJeff Brown * The route description describes the kind of destination represented by the route. 631d63957d28aaabcec588b8cde12eac16414783aebJeff Brown * It may be a user-supplied string, a model number or brand of device. 632d63957d28aaabcec588b8cde12eac16414783aebJeff Brown * </p> 633c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 634d63957d28aaabcec588b8cde12eac16414783aebJeff Brown * @return The description of the route, or null if none. 635c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 636d63957d28aaabcec588b8cde12eac16414783aebJeff Brown public String getDescription() { 637d63957d28aaabcec588b8cde12eac16414783aebJeff Brown return mDescription; 638c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 639c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 640c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 641c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Returns true if this route is enabled and may be selected. 642c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 64311417b1cfde8f1749905f2d735623af9214148afJeff Brown * @return True if this route is enabled. 644c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 645c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public boolean isEnabled() { 646c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return mEnabled; 647c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 648c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 649c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 65011417b1cfde8f1749905f2d735623af9214148afJeff Brown * Returns true if the route is in the process of connecting and is not 65111417b1cfde8f1749905f2d735623af9214148afJeff Brown * yet ready for use. 65211417b1cfde8f1749905f2d735623af9214148afJeff Brown * 65311417b1cfde8f1749905f2d735623af9214148afJeff Brown * @return True if this route is in the process of connecting. 65411417b1cfde8f1749905f2d735623af9214148afJeff Brown */ 65511417b1cfde8f1749905f2d735623af9214148afJeff Brown public boolean isConnecting() { 65611417b1cfde8f1749905f2d735623af9214148afJeff Brown return mConnecting; 65711417b1cfde8f1749905f2d735623af9214148afJeff Brown } 65811417b1cfde8f1749905f2d735623af9214148afJeff Brown 65911417b1cfde8f1749905f2d735623af9214148afJeff Brown /** 660fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * Returns true if this route is currently selected. 661c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 66211417b1cfde8f1749905f2d735623af9214148afJeff Brown * @return True if this route is currently selected. 663fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * 664fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * @see MediaRouter#getSelectedRoute 665fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown */ 666fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public boolean isSelected() { 667fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown checkCallingThread(); 668fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return sGlobal.getSelectedRoute() == this; 669fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 670fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 671fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown /** 672fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * Returns true if this route is the default route. 673fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * 67411417b1cfde8f1749905f2d735623af9214148afJeff Brown * @return True if this route is the default route. 675fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * 676fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * @see MediaRouter#getDefaultRoute 677fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown */ 678fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public boolean isDefault() { 679fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown checkCallingThread(); 680fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return sGlobal.getDefaultRoute() == this; 681fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 682fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 683fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown /** 684fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * Gets a list of {@link MediaControlIntent media control intent} filters that 685fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * describe the capabilities of this route and the media control actions that 686fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * it supports. 687fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * 688fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * @return A list of intent filters that specifies the media control intents that 689fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * this route supports. 690c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 691c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @see MediaControlIntent 692c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @see #supportsControlCategory 693c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @see #supportsControlRequest 694c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 695fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public List<IntentFilter> getControlFilters() { 696fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return mControlFilters; 697c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 698c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 699c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 70028520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown * Returns true if the route supports at least one of the capabilities 70128520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown * described by a media route selector. 70228520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown * 70328520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown * @param selector The selector that specifies the capabilities to check. 70428520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown * @return True if the route supports at least one of the capabilities 70528520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown * described in the media route selector. 70628520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown */ 70711417b1cfde8f1749905f2d735623af9214148afJeff Brown public boolean matchesSelector(MediaRouteSelector selector) { 70828520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown if (selector == null) { 70928520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown throw new IllegalArgumentException("selector must not be null"); 71028520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown } 71128520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown checkCallingThread(); 71211417b1cfde8f1749905f2d735623af9214148afJeff Brown return selector.matchesControlFilters(mControlFilters); 71328520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown } 71428520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown 71528520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown /** 716c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Returns true if the route supports the specified 717c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * {@link MediaControlIntent media control} category. 718c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * <p> 719c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Media control categories describe the capabilities of this route 720c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * such as whether it supports live audio streaming or remote playback. 721c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * </p> 722c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 723c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @param category A {@link MediaControlIntent media control} category 724c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * such as {@link MediaControlIntent#CATEGORY_LIVE_AUDIO}, 725c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * {@link MediaControlIntent#CATEGORY_LIVE_VIDEO}, 726fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * {@link MediaControlIntent#CATEGORY_REMOTE_PLAYBACK}, or a provider-defined 727c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * media control category. 72828520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown * @return True if the route supports the specified intent category. 729c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 730c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @see MediaControlIntent 731fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * @see #getControlFilters 732c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 733c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public boolean supportsControlCategory(String category) { 734c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (category == null) { 735c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown throw new IllegalArgumentException("category must not be null"); 736c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 737fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown checkCallingThread(); 738c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 739fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown int count = mControlFilters.size(); 740fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown for (int i = 0; i < count; i++) { 741fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (mControlFilters.get(i).hasCategory(category)) { 742fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return true; 743fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 744fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 745fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return false; 746c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 747c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 748c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 749c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Returns true if the route supports the specified 750c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * {@link MediaControlIntent media control} request. 751c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * <p> 752c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Media control requests are used to request the route to perform 75343f79f79a5117550a7dfedf9c65124afd163ea43Jeff Brown * actions such as starting remote playback of a media item. 754c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * </p> 755c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 756c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @param intent A {@link MediaControlIntent media control intent}. 757c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @return True if the route can handle the specified intent. 758c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 759c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @see MediaControlIntent 760fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * @see #getControlFilters 761c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 762c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public boolean supportsControlRequest(Intent intent) { 763c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (intent == null) { 764c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown throw new IllegalArgumentException("intent must not be null"); 765c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 766c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown checkCallingThread(); 767c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 768c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown ContentResolver contentResolver = sGlobal.getContentResolver(); 769fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown int count = mControlFilters.size(); 770fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown for (int i = 0; i < count; i++) { 771fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (mControlFilters.get(i).match(contentResolver, intent, true, TAG) >= 0) { 772fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return true; 773fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 774fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 775fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return false; 776c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 777c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 778c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 779c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Sends a {@link MediaControlIntent media control} request to be performed 780c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * asynchronously by the route's destination. 781c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * <p> 782c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Media control requests are used to request the route to perform 78343f79f79a5117550a7dfedf9c65124afd163ea43Jeff Brown * actions such as starting remote playback of a media item. 784c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * </p><p> 785fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * This function may only be called on a selected route. Control requests 786fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * sent to unselected routes will fail. 787c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * </p> 788c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 789c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @param intent A {@link MediaControlIntent media control intent}. 790c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @param callback A {@link ControlRequestCallback} to invoke with the result 791c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * of the request, or null if no result is required. 792c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 793c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @see MediaControlIntent 794c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 795fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public void sendControlRequest(Intent intent, ControlRequestCallback callback) { 796c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (intent == null) { 797c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown throw new IllegalArgumentException("intent must not be null"); 798c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 799c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown checkCallingThread(); 800c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 801fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown sGlobal.sendControlRequest(this, intent, callback); 802c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 803c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 804c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 805c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Gets the type of playback associated with this route. 806c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 807c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @return The type of playback associated with this route: {@link #PLAYBACK_TYPE_LOCAL} 808c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * or {@link #PLAYBACK_TYPE_REMOTE}. 809c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 810c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public int getPlaybackType() { 811c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return mPlaybackType; 812c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 813c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 814c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 815350ba6e4a1b5ec28721a098e50eaf6a508eb28f0Jeff Brown * Gets the audio stream over which the playback associated with this route is performed. 816c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 817c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @return The stream over which the playback associated with this route is performed. 818c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 819c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public int getPlaybackStream() { 820c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return mPlaybackStream; 821c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 822c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 823c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 824c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Gets information about how volume is handled on the route. 825c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 826c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @return How volume is handled on the route: {@link #PLAYBACK_VOLUME_FIXED} 827c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * or {@link #PLAYBACK_VOLUME_VARIABLE}. 828c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 829c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public int getVolumeHandling() { 830c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return mVolumeHandling; 831c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 832c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 833c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 834c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Gets the current volume for this route. Depending on the route, this may only 835c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * be valid if the route is currently selected. 836c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 837c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @return The volume at which the playback associated with this route is performed. 838c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 839c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public int getVolume() { 840c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return mVolume; 841c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 842c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 843c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 844c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Gets the maximum volume at which the playback associated with this route is performed. 845c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 846c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @return The maximum volume at which the playback associated with 847c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * this route is performed. 848c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 849c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public int getVolumeMax() { 850c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return mVolumeMax; 851c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 852c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 853c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 854c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Requests a volume change for this route asynchronously. 855c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * <p> 856c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * This function may only be called on a selected route. It will have 857c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * no effect if the route is currently unselected. 858c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * </p> 859c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 860c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @param volume The new volume value between 0 and {@link #getVolumeMax}. 861c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 862c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public void requestSetVolume(int volume) { 863c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown checkCallingThread(); 864c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown sGlobal.requestSetVolume(this, Math.min(mVolumeMax, Math.max(0, volume))); 865c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 866c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 867c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 868c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Requests an incremental volume update for this route asynchronously. 869c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * <p> 870c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * This function may only be called on a selected route. It will have 871c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * no effect if the route is currently unselected. 872c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * </p> 873c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 874c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @param delta The delta to add to the current volume. 875c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 876c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public void requestUpdateVolume(int delta) { 877c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown checkCallingThread(); 878c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (delta != 0) { 879c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown sGlobal.requestUpdateVolume(this, delta); 880c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 881c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 882c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 883c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 884c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Gets the {@link Display} that should be used by the application to show 885c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * a {@link android.app.Presentation} on an external display when this route is selected. 886c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Depending on the route, this may only be valid if the route is currently 887c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * selected. 888c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * <p> 889c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * The preferred presentation display may change independently of the route 890c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * being selected or unselected. For example, the presentation display 891c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * of the default system route may change when an external HDMI display is connected 892c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * or disconnected even though the route itself has not changed. 893c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * </p><p> 894c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * This method may return null if there is no external display associated with 895c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * the route or if the display is not ready to show UI yet. 896c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * </p><p> 897c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * The application should listen for changes to the presentation display 898c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * using the {@link Callback#onRoutePresentationDisplayChanged} callback and 899c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * show or dismiss its {@link android.app.Presentation} accordingly when the display 900c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * becomes available or is removed. 901c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * </p><p> 902c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * This method only makes sense for 903c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * {@link MediaControlIntent#CATEGORY_LIVE_VIDEO live video} routes. 904c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * </p> 905c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 906c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @return The preferred presentation display to use when this route is 907c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * selected or null if none. 908c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 909c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @see MediaControlIntent#CATEGORY_LIVE_VIDEO 910c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @see android.app.Presentation 911c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 912c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public Display getPresentationDisplay() { 913fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown checkCallingThread(); 914c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (mPresentationDisplayId >= 0 && mPresentationDisplay == null) { 915c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown mPresentationDisplay = sGlobal.getDisplay(mPresentationDisplayId); 916c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 917c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return mPresentationDisplay; 918c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 919c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 920c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 921c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Gets a collection of extra properties about this route that were supplied 922c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * by its media route provider, or null if none. 923c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 924c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public Bundle getExtras() { 925c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return mExtras; 926c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 927c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 928fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown /** 929fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * Selects this media route. 930fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown */ 931fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public void select() { 932fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown checkCallingThread(); 933fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown sGlobal.selectRoute(this); 934fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 935fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 936c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown @Override 937c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public String toString() { 938c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return "MediaRouter.RouteInfo{ name=" + mName 939d63957d28aaabcec588b8cde12eac16414783aebJeff Brown + ", description=" + mDescription 940c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown + ", enabled=" + mEnabled 94111417b1cfde8f1749905f2d735623af9214148afJeff Brown + ", connecting=" + mConnecting 942c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown + ", playbackType=" + mPlaybackType 943c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown + ", playbackStream=" + mPlaybackStream 944c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown + ", volumeHandling=" + mVolumeHandling 945c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown + ", volume=" + mVolume 946c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown + ", volumeMax=" + mVolumeMax 947c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown + ", presentationDisplayId=" + mPresentationDisplayId 948c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown + ", extras=" + mExtras 949fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown + ", providerPackageName=" + mProvider.getPackageName() 950fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown + " }"; 951fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 952fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 95311417b1cfde8f1749905f2d735623af9214148afJeff Brown int updateDescriptor(MediaRouteDescriptor descriptor) { 954fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown int changes = 0; 955fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (mDescriptor != descriptor) { 956fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mDescriptor = descriptor; 957fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (descriptor != null) { 958fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (!equal(mName, descriptor.getName())) { 959fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mName = descriptor.getName(); 960fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown changes |= CHANGE_GENERAL; 961fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 962d63957d28aaabcec588b8cde12eac16414783aebJeff Brown if (!equal(mDescription, descriptor.getDescription())) { 963d63957d28aaabcec588b8cde12eac16414783aebJeff Brown mDescription = descriptor.getDescription(); 964fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown changes |= CHANGE_GENERAL; 965fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 966fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (mEnabled != descriptor.isEnabled()) { 967fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mEnabled = descriptor.isEnabled(); 968fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown changes |= CHANGE_GENERAL; 969fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 97011417b1cfde8f1749905f2d735623af9214148afJeff Brown if (mConnecting != descriptor.isConnecting()) { 97111417b1cfde8f1749905f2d735623af9214148afJeff Brown mConnecting = descriptor.isConnecting(); 97211417b1cfde8f1749905f2d735623af9214148afJeff Brown changes |= CHANGE_GENERAL; 97311417b1cfde8f1749905f2d735623af9214148afJeff Brown } 97411417b1cfde8f1749905f2d735623af9214148afJeff Brown if (!mControlFilters.equals(descriptor.getControlFilters())) { 975fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mControlFilters.clear(); 97611417b1cfde8f1749905f2d735623af9214148afJeff Brown mControlFilters.addAll(descriptor.getControlFilters()); 977fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown changes |= CHANGE_GENERAL; 978fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 979fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (mPlaybackType != descriptor.getPlaybackType()) { 980fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mPlaybackType = descriptor.getPlaybackType(); 981fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown changes |= CHANGE_GENERAL; 982fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 983fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (mPlaybackStream != descriptor.getPlaybackStream()) { 984fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mPlaybackStream = descriptor.getPlaybackStream(); 985fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown changes |= CHANGE_GENERAL; 986fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 987fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (mVolumeHandling != descriptor.getVolumeHandling()) { 988fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mVolumeHandling = descriptor.getVolumeHandling(); 989fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown changes |= CHANGE_GENERAL | CHANGE_VOLUME; 990fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 991fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (mVolume != descriptor.getVolume()) { 992fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mVolume = descriptor.getVolume(); 993fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown changes |= CHANGE_GENERAL | CHANGE_VOLUME; 994fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 995fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (mVolumeMax != descriptor.getVolumeMax()) { 996fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mVolumeMax = descriptor.getVolumeMax(); 997fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown changes |= CHANGE_GENERAL | CHANGE_VOLUME; 998fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 999fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (mPresentationDisplayId != descriptor.getPresentationDisplayId()) { 1000fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mPresentationDisplayId = descriptor.getPresentationDisplayId(); 1001fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mPresentationDisplay = null; 1002fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown changes |= CHANGE_GENERAL | CHANGE_PRESENTATION_DISPLAY; 1003fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 1004fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (!equal(mExtras, descriptor.getExtras())) { 1005fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mExtras = descriptor.getExtras(); 1006fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown changes |= CHANGE_GENERAL; 1007fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 1008fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 1009fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 1010fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return changes; 1011fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 1012fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 1013fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown String getDescriptorId() { 1014fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return mDescriptorId; 1015fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 1016fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 1017fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown MediaRouteProvider getProviderInstance() { 1018fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return mProvider.getProviderInstance(); 1019fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 1020fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 1021fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 1022fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown /** 1023fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * Provides information about a media route provider. 1024fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * <p> 1025fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * This object may be used to determine which media route provider has 1026fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * published a particular route. 1027fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * </p> 1028fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown */ 1029fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public static final class ProviderInfo { 1030fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private final MediaRouteProvider mProviderInstance; 1031fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private final ArrayList<RouteInfo> mRoutes = new ArrayList<RouteInfo>(); 103211417b1cfde8f1749905f2d735623af9214148afJeff Brown private final ArrayList<IntentFilter> mDiscoverableControlFilters = 103311417b1cfde8f1749905f2d735623af9214148afJeff Brown new ArrayList<IntentFilter>(); 1034fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 1035fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private final ProviderMetadata mMetadata; 103611417b1cfde8f1749905f2d735623af9214148afJeff Brown private MediaRouteProviderDescriptor mDescriptor; 1037fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private Resources mResources; 1038fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private boolean mResourcesNotAvailable; 1039fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 1040fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown ProviderInfo(MediaRouteProvider provider) { 1041fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mProviderInstance = provider; 1042fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mMetadata = provider.getMetadata(); 1043fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 1044fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 1045fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown /** 1046fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * Gets the provider's underlying {@link MediaRouteProvider} instance. 1047fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown */ 1048fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public MediaRouteProvider getProviderInstance() { 1049fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown checkCallingThread(); 1050fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return mProviderInstance; 1051fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 1052fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 1053fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown /** 1054fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * Gets the package name of the media route provider service. 1055fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown */ 1056fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public String getPackageName() { 1057fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return mMetadata.getPackageName(); 1058fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 1059fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 1060fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown /** 1061fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * Gets the {@link MediaRouter.RouteInfo routes} published by this route provider. 1062fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown */ 1063fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public List<RouteInfo> getRoutes() { 1064fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown checkCallingThread(); 1065fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return mRoutes; 1066fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 1067fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 106828520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown /** 106928520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown * Returns true if the provider requires active scans to discover routes. 107011417b1cfde8f1749905f2d735623af9214148afJeff Brown * <p> 107111417b1cfde8f1749905f2d735623af9214148afJeff Brown * To provide the best user experience, a media route provider should passively 107211417b1cfde8f1749905f2d735623af9214148afJeff Brown * discover and publish changes to route descriptors in the background. 107311417b1cfde8f1749905f2d735623af9214148afJeff Brown * However, for some providers, scanning for routes may use a significant 107411417b1cfde8f1749905f2d735623af9214148afJeff Brown * amount of power or may interfere with wireless network connectivity. 107511417b1cfde8f1749905f2d735623af9214148afJeff Brown * If this is the case, then the provider will indicate that it requires 107611417b1cfde8f1749905f2d735623af9214148afJeff Brown * active scans to discover routes by setting this flag. Active scans 107711417b1cfde8f1749905f2d735623af9214148afJeff Brown * will be performed when the user opens the route chooser dialog. 107811417b1cfde8f1749905f2d735623af9214148afJeff Brown * </p> 107928520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown */ 108028520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown public boolean isActiveScanRequired() { 108128520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown checkCallingThread(); 108228520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown return mDescriptor != null && mDescriptor.isActiveScanRequired(); 108328520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown } 108428520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown 108511417b1cfde8f1749905f2d735623af9214148afJeff Brown /** 108611417b1cfde8f1749905f2d735623af9214148afJeff Brown * Gets a list of {@link MediaControlIntent media route control filters} that 108711417b1cfde8f1749905f2d735623af9214148afJeff Brown * describe the union of capabilities of all routes that this provider can 108811417b1cfde8f1749905f2d735623af9214148afJeff Brown * possibly discover. 108911417b1cfde8f1749905f2d735623af9214148afJeff Brown * <p> 109011417b1cfde8f1749905f2d735623af9214148afJeff Brown * Because a route provider may not know what to look for until an 109111417b1cfde8f1749905f2d735623af9214148afJeff Brown * application actually asks for it, the contents of the discoverable control 109211417b1cfde8f1749905f2d735623af9214148afJeff Brown * filter list may change depending on the route selectors that applications have 109311417b1cfde8f1749905f2d735623af9214148afJeff Brown * actually specified when {@link MediaRouter#addCallback registering callbacks} 109411417b1cfde8f1749905f2d735623af9214148afJeff Brown * on the media router to discover routes. 109511417b1cfde8f1749905f2d735623af9214148afJeff Brown * </p> 109611417b1cfde8f1749905f2d735623af9214148afJeff Brown */ 109711417b1cfde8f1749905f2d735623af9214148afJeff Brown public List<IntentFilter> getDiscoverableControlFilters() { 109811417b1cfde8f1749905f2d735623af9214148afJeff Brown checkCallingThread(); 109911417b1cfde8f1749905f2d735623af9214148afJeff Brown return mDiscoverableControlFilters; 110011417b1cfde8f1749905f2d735623af9214148afJeff Brown } 110111417b1cfde8f1749905f2d735623af9214148afJeff Brown 1102fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown Resources getResources() { 1103fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (mResources == null && !mResourcesNotAvailable) { 1104fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown String packageName = getPackageName(); 1105fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown Context context = sGlobal.getProviderContext(packageName); 1106fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (context != null) { 1107fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mResources = context.getResources(); 1108fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } else { 1109fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown Log.w(TAG, "Unable to obtain resources for route provider package: " 1110fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown + packageName); 1111fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mResourcesNotAvailable = true; 1112fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 1113fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 1114fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return mResources; 1115fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 1116fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 111711417b1cfde8f1749905f2d735623af9214148afJeff Brown boolean updateDescriptor(MediaRouteProviderDescriptor descriptor) { 1118fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (mDescriptor != descriptor) { 1119fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mDescriptor = descriptor; 11202ef36d857302c5cd738c7c8bdec53d31feebebbaJeff Brown if (descriptor != null) { 11212ef36d857302c5cd738c7c8bdec53d31feebebbaJeff Brown if (!mDiscoverableControlFilters.equals( 11222ef36d857302c5cd738c7c8bdec53d31feebebbaJeff Brown descriptor.getDiscoverableControlFilters())) { 11232ef36d857302c5cd738c7c8bdec53d31feebebbaJeff Brown mDiscoverableControlFilters.clear(); 11243d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown mDiscoverableControlFilters.addAll( 11253d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown descriptor.getDiscoverableControlFilters()); 11262ef36d857302c5cd738c7c8bdec53d31feebebbaJeff Brown } 112711417b1cfde8f1749905f2d735623af9214148afJeff Brown } 1128fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return true; 1129fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 1130fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return false; 1131fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 1132fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 1133fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown int findRouteByDescriptorId(String id) { 1134fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown final int count = mRoutes.size(); 1135fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown for (int i = 0; i < count; i++) { 1136fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (mRoutes.get(i).mDescriptorId.equals(id)) { 1137fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return i; 1138fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 1139fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 1140fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return -1; 1141fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 1142fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 1143fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown @Override 1144fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public String toString() { 1145fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return "MediaRouter.RouteProviderInfo{ packageName=" + getPackageName() 114611417b1cfde8f1749905f2d735623af9214148afJeff Brown + ", isActiveScanRequired=" + isActiveScanRequired() 1147c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown + " }"; 1148c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1149c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1150c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1151c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 1152c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Interface for receiving events about media routing changes. 1153c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * All methods of this interface will be called from the application's main thread. 1154c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * <p> 1155c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * A Callback will only receive events relevant to routes that the callback 115611417b1cfde8f1749905f2d735623af9214148afJeff Brown * was registered for unless the {@link MediaRouter#CALLBACK_FLAG_UNFILTERED_EVENTS} 115711417b1cfde8f1749905f2d735623af9214148afJeff Brown * flag was specified in {@link MediaRouter#addCallback(MediaRouteSelector, Callback, int)}. 1158c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * </p> 1159c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 116011417b1cfde8f1749905f2d735623af9214148afJeff Brown * @see MediaRouter#addCallback(MediaRouteSelector, Callback, int) 1161c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @see MediaRouter#removeCallback(Callback) 1162c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 1163c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public static abstract class Callback { 1164c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 1165fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * Called when the supplied media route becomes selected as the active route. 1166c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 1167fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * @param router The media router reporting the event. 1168c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @param route The route that has been selected. 1169c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 1170c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public void onRouteSelected(MediaRouter router, RouteInfo route) { 1171c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1172c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1173c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 1174fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * Called when the supplied media route becomes unselected as the active route. 1175c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 1176fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * @param router The media router reporting the event. 1177c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @param route The route that has been unselected. 1178c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 1179c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public void onRouteUnselected(MediaRouter router, RouteInfo route) { 1180c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1181c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1182c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 1183fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * Called when a media route has been added. 1184c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 1185fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * @param router The media router reporting the event. 1186c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @param route The route that has become available for use. 1187c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 1188c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public void onRouteAdded(MediaRouter router, RouteInfo route) { 1189c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1190c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1191c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 1192fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * Called when a media route has been removed. 1193c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 1194fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * @param router The media router reporting the event. 1195c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @param route The route that has been removed from availability. 1196c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 1197c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public void onRouteRemoved(MediaRouter router, RouteInfo route) { 1198c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1199c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1200c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 1201fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * Called when a property of the indicated media route has changed. 1202c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 1203fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * @param router The media router reporting the event. 1204c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @param route The route that was changed. 1205c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 1206c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public void onRouteChanged(MediaRouter router, RouteInfo route) { 1207c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1208c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1209c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 1210fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * Called when a media route's volume changes. 1211c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 1212fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * @param router The media router reporting the event. 1213c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @param route The route whose volume changed. 1214c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 1215c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public void onRouteVolumeChanged(MediaRouter router, RouteInfo route) { 1216c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1217c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1218c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 1219fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * Called when a media route's presentation display changes. 1220c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * <p> 1221c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * This method is called whenever the route's presentation display becomes 1222fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * available, is removed or has changes to some of its properties (such as its size). 1223c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * </p> 1224c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 1225fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * @param router The media router reporting the event. 1226c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @param route The route whose presentation display changed. 1227c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 1228c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @see RouteInfo#getPresentationDisplay() 1229c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 1230c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public void onRoutePresentationDisplayChanged(MediaRouter router, RouteInfo route) { 1231c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1232fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 1233fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown /** 1234fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * Called when a media route provider has been added. 1235fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * 1236fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * @param router The media router reporting the event. 1237fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * @param provider The provider that has become available for use. 1238fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown */ 1239fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public void onProviderAdded(MediaRouter router, ProviderInfo provider) { 1240fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 1241fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 1242fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown /** 1243fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * Called when a media route provider has been removed. 1244fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * 1245fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * @param router The media router reporting the event. 1246fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * @param provider The provider that has been removed from availability. 1247fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown */ 1248fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public void onProviderRemoved(MediaRouter router, ProviderInfo provider) { 1249fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 125011417b1cfde8f1749905f2d735623af9214148afJeff Brown 125111417b1cfde8f1749905f2d735623af9214148afJeff Brown /** 125211417b1cfde8f1749905f2d735623af9214148afJeff Brown * Called when a property of the indicated media route provider has changed. 125311417b1cfde8f1749905f2d735623af9214148afJeff Brown * 125411417b1cfde8f1749905f2d735623af9214148afJeff Brown * @param router The media router reporting the event. 125511417b1cfde8f1749905f2d735623af9214148afJeff Brown * @param provider The provider that was changed. 125611417b1cfde8f1749905f2d735623af9214148afJeff Brown */ 125711417b1cfde8f1749905f2d735623af9214148afJeff Brown public void onProviderChanged(MediaRouter router, ProviderInfo provider) { 125811417b1cfde8f1749905f2d735623af9214148afJeff Brown } 1259c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1260c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1261c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 1262c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Callback which is invoked with the result of a media control request. 1263c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 1264c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @see RouteInfo#sendControlRequest 1265c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 1266fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public static abstract class ControlRequestCallback { 1267c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 12683d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown * Called when a media control request succeeds. 12693d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown * 12703d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown * @param data Result data, or null if none. 12713d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown * Contents depend on the {@link MediaControlIntent media control action}. 1272c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 12733d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown public void onResult(Bundle data) { 12743d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown } 1275c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1276c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 12773d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown * Called when a media control request fails. 1278c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 12793d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown * @param error A localized error message which may be shown to the user, or null 12803d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown * if the cause of the error is unclear. 12813d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown * @param data Error data, or null if none. 12823d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown * Contents depend on the {@link MediaControlIntent media control action}. 1283c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 12843d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown public void onError(String error, Bundle data) { 1285c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1286c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1287c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 128811417b1cfde8f1749905f2d735623af9214148afJeff Brown private static final class CallbackRecord { 12899fcedc160282e6620f409ea46bf6728b35d011ddJeff Brown public final MediaRouter mRouter; 129011417b1cfde8f1749905f2d735623af9214148afJeff Brown public final Callback mCallback; 129111417b1cfde8f1749905f2d735623af9214148afJeff Brown public MediaRouteSelector mSelector; 129211417b1cfde8f1749905f2d735623af9214148afJeff Brown public int mFlags; 129311417b1cfde8f1749905f2d735623af9214148afJeff Brown 12949fcedc160282e6620f409ea46bf6728b35d011ddJeff Brown public CallbackRecord(MediaRouter router, Callback callback) { 12959fcedc160282e6620f409ea46bf6728b35d011ddJeff Brown mRouter = router; 129611417b1cfde8f1749905f2d735623af9214148afJeff Brown mCallback = callback; 129711417b1cfde8f1749905f2d735623af9214148afJeff Brown mSelector = MediaRouteSelector.EMPTY; 129811417b1cfde8f1749905f2d735623af9214148afJeff Brown } 129911417b1cfde8f1749905f2d735623af9214148afJeff Brown 130011417b1cfde8f1749905f2d735623af9214148afJeff Brown public boolean filterRouteEvent(RouteInfo route) { 130111417b1cfde8f1749905f2d735623af9214148afJeff Brown return (mFlags & CALLBACK_FLAG_UNFILTERED_EVENTS) != 0 130211417b1cfde8f1749905f2d735623af9214148afJeff Brown || route.matchesSelector(mSelector); 130311417b1cfde8f1749905f2d735623af9214148afJeff Brown } 130411417b1cfde8f1749905f2d735623af9214148afJeff Brown } 130511417b1cfde8f1749905f2d735623af9214148afJeff Brown 1306c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 1307c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Global state for the media router. 1308c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * <p> 1309c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Media routes and media route providers are global to the process; their 1310c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * state and the bulk of the media router implementation lives here. 1311c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * </p> 1312c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 1313c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown private static final class GlobalMediaRouter implements SystemMediaRouteProvider.SyncCallback { 1314c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown private final Context mApplicationContext; 1315fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private final MediaRouter mApplicationRouter; 13169fcedc160282e6620f409ea46bf6728b35d011ddJeff Brown private final ArrayList<WeakReference<MediaRouter>> mRouters = 13179fcedc160282e6620f409ea46bf6728b35d011ddJeff Brown new ArrayList<WeakReference<MediaRouter>>(); 1318c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown private final ArrayList<RouteInfo> mRoutes = new ArrayList<RouteInfo>(); 1319fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private final ArrayList<ProviderInfo> mProviders = 1320fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown new ArrayList<ProviderInfo>(); 1321c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown private final ProviderCallback mProviderCallback = new ProviderCallback(); 1322c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown private final CallbackHandler mCallbackHandler = new CallbackHandler(); 1323c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown private final DisplayManagerCompat mDisplayManager; 1324c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown private final SystemMediaRouteProvider mSystemProvider; 1325c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1326fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private RegisteredMediaRouteProviderWatcher mRegisteredProviderWatcher; 1327c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown private RouteInfo mDefaultRoute; 1328c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown private RouteInfo mSelectedRoute; 1329c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown private MediaRouteProvider.RouteController mSelectedRouteController; 133011417b1cfde8f1749905f2d735623af9214148afJeff Brown private MediaRouteDiscoveryRequest mDiscoveryRequest; 1331c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1332c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown GlobalMediaRouter(Context applicationContext) { 1333c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown mApplicationContext = applicationContext; 1334c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown mDisplayManager = DisplayManagerCompat.getInstance(applicationContext); 1335fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mApplicationRouter = getRouter(applicationContext); 1336fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 1337fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown // Add the system media route provider for interoperating with 1338fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown // the framework media router. This one is special and receives 1339fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown // synchronization messages from the media router. 1340c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown mSystemProvider = SystemMediaRouteProvider.obtain(applicationContext, this); 1341fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown addProvider(mSystemProvider); 1342fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 1343fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 1344fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public void start() { 1345fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown // Start watching for routes published by registered media route 1346fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown // provider services. 1347fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mRegisteredProviderWatcher = new RegisteredMediaRouteProviderWatcher( 1348fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mApplicationContext, mApplicationRouter); 1349fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mRegisteredProviderWatcher.start(); 1350c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1351c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1352c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public MediaRouter getRouter(Context context) { 13539fcedc160282e6620f409ea46bf6728b35d011ddJeff Brown MediaRouter router; 13549fcedc160282e6620f409ea46bf6728b35d011ddJeff Brown for (int i = mRouters.size(); --i >= 0; ) { 13559fcedc160282e6620f409ea46bf6728b35d011ddJeff Brown router = mRouters.get(i).get(); 13569fcedc160282e6620f409ea46bf6728b35d011ddJeff Brown if (router == null) { 13579fcedc160282e6620f409ea46bf6728b35d011ddJeff Brown mRouters.remove(i); 13589fcedc160282e6620f409ea46bf6728b35d011ddJeff Brown } else if (router.mContext == context) { 13599fcedc160282e6620f409ea46bf6728b35d011ddJeff Brown return router; 13609fcedc160282e6620f409ea46bf6728b35d011ddJeff Brown } 1361c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 13629fcedc160282e6620f409ea46bf6728b35d011ddJeff Brown router = new MediaRouter(context); 13639fcedc160282e6620f409ea46bf6728b35d011ddJeff Brown mRouters.add(new WeakReference<MediaRouter>(router)); 1364c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return router; 1365c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1366c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1367c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public ContentResolver getContentResolver() { 1368c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return mApplicationContext.getContentResolver(); 1369c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1370c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1371fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public Context getProviderContext(String packageName) { 1372fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (packageName.equals(SystemMediaRouteProvider.PACKAGE_NAME)) { 1373fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return mApplicationContext; 1374fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 1375fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown try { 1376fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return mApplicationContext.createPackageContext( 1377fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown packageName, Context.CONTEXT_RESTRICTED); 1378fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } catch (NameNotFoundException ex) { 1379fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return null; 1380fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 1381fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 1382fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 1383c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public Display getDisplay(int displayId) { 1384c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return mDisplayManager.getDisplay(displayId); 1385c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1386c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1387fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public void sendControlRequest(RouteInfo route, 1388c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown Intent intent, ControlRequestCallback callback) { 1389c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (route == mSelectedRoute && mSelectedRouteController != null) { 1390129abf73ce9be1bc172b945263c7975ad1a3006fJeff Brown if (mSelectedRouteController.onControlRequest(intent, callback)) { 1391fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return; 1392fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 1393fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 1394fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (callback != null) { 13953d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown callback.onError(null, null); 1396c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1397c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1398c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1399c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public void requestSetVolume(RouteInfo route, int volume) { 1400c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (route == mSelectedRoute && mSelectedRouteController != null) { 1401129abf73ce9be1bc172b945263c7975ad1a3006fJeff Brown mSelectedRouteController.onSetVolume(volume); 1402c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1403c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1404c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1405c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public void requestUpdateVolume(RouteInfo route, int delta) { 1406c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (route == mSelectedRoute && mSelectedRouteController != null) { 1407129abf73ce9be1bc172b945263c7975ad1a3006fJeff Brown mSelectedRouteController.onUpdateVolume(delta); 1408c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1409c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1410c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1411c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public List<RouteInfo> getRoutes() { 1412c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return mRoutes; 1413c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1414c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1415fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public List<ProviderInfo> getProviders() { 1416fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return mProviders; 1417fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 1418fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 1419c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public RouteInfo getDefaultRoute() { 1420c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (mDefaultRoute == null) { 1421c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown // This should never happen once the media router has been fully 1422c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown // initialized but it is good to check for the error in case there 1423c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown // is a bug in provider initialization. 1424c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown throw new IllegalStateException("There is no default route. " 1425c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown + "The media router has not yet been fully initialized."); 1426c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1427c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return mDefaultRoute; 1428c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1429c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1430c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public RouteInfo getSelectedRoute() { 1431c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (mSelectedRoute == null) { 1432c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown // This should never happen once the media router has been fully 1433c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown // initialized but it is good to check for the error in case there 1434c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown // is a bug in provider initialization. 1435c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown throw new IllegalStateException("There is no currently selected route. " 1436c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown + "The media router has not yet been fully initialized."); 1437c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1438c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return mSelectedRoute; 1439c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1440c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1441c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public void selectRoute(RouteInfo route) { 1442c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (!mRoutes.contains(route)) { 1443c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown Log.w(TAG, "Ignoring attempt to select removed route: " + route); 1444c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return; 1445c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1446c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (!route.mEnabled) { 1447c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown Log.w(TAG, "Ignoring attempt to select disabled route: " + route); 1448c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return; 1449c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1450c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1451c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown setSelectedRouteInternal(route); 1452c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1453c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 145411417b1cfde8f1749905f2d735623af9214148afJeff Brown public boolean isRouteAvailable(MediaRouteSelector selector, int flags) { 145511417b1cfde8f1749905f2d735623af9214148afJeff Brown // Check whether any existing routes match the selector. 145611417b1cfde8f1749905f2d735623af9214148afJeff Brown final int routeCount = mRoutes.size(); 145711417b1cfde8f1749905f2d735623af9214148afJeff Brown for (int i = 0; i < routeCount; i++) { 145811417b1cfde8f1749905f2d735623af9214148afJeff Brown RouteInfo route = mRoutes.get(i); 145911417b1cfde8f1749905f2d735623af9214148afJeff Brown if ((flags & AVAILABILITY_FLAG_IGNORE_DEFAULT_ROUTE) != 0 146011417b1cfde8f1749905f2d735623af9214148afJeff Brown && route.isDefault()) { 146111417b1cfde8f1749905f2d735623af9214148afJeff Brown continue; 146211417b1cfde8f1749905f2d735623af9214148afJeff Brown } 146311417b1cfde8f1749905f2d735623af9214148afJeff Brown if (route.matchesSelector(selector)) { 146411417b1cfde8f1749905f2d735623af9214148afJeff Brown return true; 146511417b1cfde8f1749905f2d735623af9214148afJeff Brown } 146611417b1cfde8f1749905f2d735623af9214148afJeff Brown } 146711417b1cfde8f1749905f2d735623af9214148afJeff Brown 146811417b1cfde8f1749905f2d735623af9214148afJeff Brown // Check whether any provider could possibly discover a matching route 146911417b1cfde8f1749905f2d735623af9214148afJeff Brown // if a required active scan were performed. 147011417b1cfde8f1749905f2d735623af9214148afJeff Brown if ((flags & AVAILABILITY_FLAG_CONSIDER_ACTIVE_SCAN) != 0) { 147111417b1cfde8f1749905f2d735623af9214148afJeff Brown final int providerCount = mProviders.size(); 147211417b1cfde8f1749905f2d735623af9214148afJeff Brown for (int i = 0; i < providerCount; i++) { 147311417b1cfde8f1749905f2d735623af9214148afJeff Brown ProviderInfo provider = mProviders.get(i); 147411417b1cfde8f1749905f2d735623af9214148afJeff Brown if (provider.isActiveScanRequired() && selector.matchesControlFilters( 147511417b1cfde8f1749905f2d735623af9214148afJeff Brown provider.getDiscoverableControlFilters())) { 147611417b1cfde8f1749905f2d735623af9214148afJeff Brown return true; 147711417b1cfde8f1749905f2d735623af9214148afJeff Brown } 147811417b1cfde8f1749905f2d735623af9214148afJeff Brown } 147911417b1cfde8f1749905f2d735623af9214148afJeff Brown } 148011417b1cfde8f1749905f2d735623af9214148afJeff Brown 148111417b1cfde8f1749905f2d735623af9214148afJeff Brown // It doesn't look like we can find a matching route right now. 148211417b1cfde8f1749905f2d735623af9214148afJeff Brown return false; 148311417b1cfde8f1749905f2d735623af9214148afJeff Brown } 148411417b1cfde8f1749905f2d735623af9214148afJeff Brown 148511417b1cfde8f1749905f2d735623af9214148afJeff Brown public void updateDiscoveryRequest() { 148611417b1cfde8f1749905f2d735623af9214148afJeff Brown // Combine all of the callback selectors and active scan flags. 148711417b1cfde8f1749905f2d735623af9214148afJeff Brown boolean activeScan = false; 148811417b1cfde8f1749905f2d735623af9214148afJeff Brown MediaRouteSelector.Builder builder = new MediaRouteSelector.Builder(); 14899fcedc160282e6620f409ea46bf6728b35d011ddJeff Brown for (int i = mRouters.size(); --i >= 0; ) { 14909fcedc160282e6620f409ea46bf6728b35d011ddJeff Brown MediaRouter router = mRouters.get(i).get(); 14919fcedc160282e6620f409ea46bf6728b35d011ddJeff Brown if (router == null) { 14929fcedc160282e6620f409ea46bf6728b35d011ddJeff Brown mRouters.remove(i); 14939fcedc160282e6620f409ea46bf6728b35d011ddJeff Brown } else { 14949fcedc160282e6620f409ea46bf6728b35d011ddJeff Brown final int count = router.mCallbackRecords.size(); 14959fcedc160282e6620f409ea46bf6728b35d011ddJeff Brown for (int j = 0; j < count; j++) { 14969fcedc160282e6620f409ea46bf6728b35d011ddJeff Brown CallbackRecord callback = router.mCallbackRecords.get(j); 14979fcedc160282e6620f409ea46bf6728b35d011ddJeff Brown builder.addSelector(callback.mSelector); 14989fcedc160282e6620f409ea46bf6728b35d011ddJeff Brown if ((callback.mFlags & CALLBACK_FLAG_ACTIVE_SCAN) != 0) { 14999fcedc160282e6620f409ea46bf6728b35d011ddJeff Brown activeScan = true; 15009fcedc160282e6620f409ea46bf6728b35d011ddJeff Brown } 150111417b1cfde8f1749905f2d735623af9214148afJeff Brown } 150211417b1cfde8f1749905f2d735623af9214148afJeff Brown } 150311417b1cfde8f1749905f2d735623af9214148afJeff Brown } 150411417b1cfde8f1749905f2d735623af9214148afJeff Brown MediaRouteSelector selector = builder.build(); 150511417b1cfde8f1749905f2d735623af9214148afJeff Brown 150611417b1cfde8f1749905f2d735623af9214148afJeff Brown // Create a new discovery request. 150711417b1cfde8f1749905f2d735623af9214148afJeff Brown if (mDiscoveryRequest != null 150811417b1cfde8f1749905f2d735623af9214148afJeff Brown && mDiscoveryRequest.getSelector().equals(selector) 150911417b1cfde8f1749905f2d735623af9214148afJeff Brown && mDiscoveryRequest.isActiveScan() == activeScan) { 151011417b1cfde8f1749905f2d735623af9214148afJeff Brown return; // no change 151111417b1cfde8f1749905f2d735623af9214148afJeff Brown } 151211417b1cfde8f1749905f2d735623af9214148afJeff Brown if (selector.isEmpty() && !activeScan) { 151311417b1cfde8f1749905f2d735623af9214148afJeff Brown // Discovery is not needed. 151411417b1cfde8f1749905f2d735623af9214148afJeff Brown if (mDiscoveryRequest == null) { 151511417b1cfde8f1749905f2d735623af9214148afJeff Brown return; // no change 151611417b1cfde8f1749905f2d735623af9214148afJeff Brown } 151711417b1cfde8f1749905f2d735623af9214148afJeff Brown mDiscoveryRequest = null; 151811417b1cfde8f1749905f2d735623af9214148afJeff Brown } else { 151911417b1cfde8f1749905f2d735623af9214148afJeff Brown // Discovery is needed. 152011417b1cfde8f1749905f2d735623af9214148afJeff Brown mDiscoveryRequest = new MediaRouteDiscoveryRequest(selector, activeScan); 152111417b1cfde8f1749905f2d735623af9214148afJeff Brown } 152211417b1cfde8f1749905f2d735623af9214148afJeff Brown if (DEBUG) { 152311417b1cfde8f1749905f2d735623af9214148afJeff Brown Log.d(TAG, "Updated discovery request: " + mDiscoveryRequest); 152411417b1cfde8f1749905f2d735623af9214148afJeff Brown } 152511417b1cfde8f1749905f2d735623af9214148afJeff Brown 152611417b1cfde8f1749905f2d735623af9214148afJeff Brown // Notify providers. 152711417b1cfde8f1749905f2d735623af9214148afJeff Brown final int providerCount = mProviders.size(); 152811417b1cfde8f1749905f2d735623af9214148afJeff Brown for (int i = 0; i < providerCount; i++) { 152911417b1cfde8f1749905f2d735623af9214148afJeff Brown mProviders.get(i).mProviderInstance.setDiscoveryRequest(mDiscoveryRequest); 153028520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown } 153128520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown } 153228520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown 1533fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public void addProvider(MediaRouteProvider providerInstance) { 1534fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown int index = findProviderInfo(providerInstance); 1535c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (index < 0) { 1536c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown // 1. Add the provider to the list. 1537fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown ProviderInfo provider = new ProviderInfo(providerInstance); 1538fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mProviders.add(provider); 153911417b1cfde8f1749905f2d735623af9214148afJeff Brown if (DEBUG) { 154011417b1cfde8f1749905f2d735623af9214148afJeff Brown Log.d(TAG, "Provider added: " + provider); 154111417b1cfde8f1749905f2d735623af9214148afJeff Brown } 1542fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mCallbackHandler.post(CallbackHandler.MSG_PROVIDER_ADDED, provider); 1543c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown // 2. Create the provider's contents. 1544fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown updateProviderContents(provider, providerInstance.getDescriptor()); 1545c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown // 3. Register the provider callback. 154611417b1cfde8f1749905f2d735623af9214148afJeff Brown providerInstance.setCallback(mProviderCallback); 154711417b1cfde8f1749905f2d735623af9214148afJeff Brown // 4. Set the discovery request. 154811417b1cfde8f1749905f2d735623af9214148afJeff Brown providerInstance.setDiscoveryRequest(mDiscoveryRequest); 1549c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1550c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1551c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1552fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public void removeProvider(MediaRouteProvider providerInstance) { 1553fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown int index = findProviderInfo(providerInstance); 1554c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (index >= 0) { 155511417b1cfde8f1749905f2d735623af9214148afJeff Brown // 1. Unregister the provider callback. 155611417b1cfde8f1749905f2d735623af9214148afJeff Brown providerInstance.setCallback(null); 155711417b1cfde8f1749905f2d735623af9214148afJeff Brown // 2. Clear the discovery request. 155811417b1cfde8f1749905f2d735623af9214148afJeff Brown providerInstance.setDiscoveryRequest(null); 155928520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown // 3. Delete the provider's contents. 1560fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown ProviderInfo provider = mProviders.get(index); 1561fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown updateProviderContents(provider, null); 156228520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown // 4. Remove the provider from the list. 156311417b1cfde8f1749905f2d735623af9214148afJeff Brown if (DEBUG) { 156411417b1cfde8f1749905f2d735623af9214148afJeff Brown Log.d(TAG, "Provider removed: " + provider); 156511417b1cfde8f1749905f2d735623af9214148afJeff Brown } 1566fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mCallbackHandler.post(CallbackHandler.MSG_PROVIDER_REMOVED, provider); 1567fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mProviders.remove(index); 1568c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1569c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1570c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1571fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private void updateProviderDescriptor(MediaRouteProvider providerInstance, 157211417b1cfde8f1749905f2d735623af9214148afJeff Brown MediaRouteProviderDescriptor descriptor) { 1573fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown int index = findProviderInfo(providerInstance); 1574c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (index >= 0) { 1575fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown // Update the provider's contents. 1576fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown ProviderInfo provider = mProviders.get(index); 1577fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown updateProviderContents(provider, descriptor); 1578c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1579c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1580c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1581fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private int findProviderInfo(MediaRouteProvider providerInstance) { 1582fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown final int count = mProviders.size(); 1583c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown for (int i = 0; i < count; i++) { 1584fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (mProviders.get(i).mProviderInstance == providerInstance) { 1585c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return i; 1586c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1587c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1588c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return -1; 1589c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1590c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1591fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private void updateProviderContents(ProviderInfo provider, 159211417b1cfde8f1749905f2d735623af9214148afJeff Brown MediaRouteProviderDescriptor providerDescriptor) { 1593fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (provider.updateDescriptor(providerDescriptor)) { 1594c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown // Update all existing routes and reorder them to match 1595c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown // the order of their descriptors. 1596c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown int targetIndex = 0; 1597c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (providerDescriptor != null) { 1598fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (providerDescriptor.isValid()) { 159911417b1cfde8f1749905f2d735623af9214148afJeff Brown final List<MediaRouteDescriptor> routeDescriptors = 160011417b1cfde8f1749905f2d735623af9214148afJeff Brown providerDescriptor.getRoutes(); 160111417b1cfde8f1749905f2d735623af9214148afJeff Brown final int routeCount = routeDescriptors.size(); 160211417b1cfde8f1749905f2d735623af9214148afJeff Brown for (int i = 0; i < routeCount; i++) { 160311417b1cfde8f1749905f2d735623af9214148afJeff Brown final MediaRouteDescriptor routeDescriptor = routeDescriptors.get(i); 1604c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown final String id = routeDescriptor.getId(); 1605fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown final int sourceIndex = provider.findRouteByDescriptorId(id); 1606c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (sourceIndex < 0) { 1607c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown // 1. Add the route to the list. 1608fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown RouteInfo route = new RouteInfo(provider, id); 1609fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown provider.mRoutes.add(targetIndex++, route); 1610c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown mRoutes.add(route); 1611c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown // 2. Create the route's contents. 1612c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown route.updateDescriptor(routeDescriptor); 1613fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown // 3. Notify clients about addition. 161411417b1cfde8f1749905f2d735623af9214148afJeff Brown if (DEBUG) { 161511417b1cfde8f1749905f2d735623af9214148afJeff Brown Log.d(TAG, "Route added: " + route); 161611417b1cfde8f1749905f2d735623af9214148afJeff Brown } 1617c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown mCallbackHandler.post(CallbackHandler.MSG_ROUTE_ADDED, route); 1618fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } else if (sourceIndex < targetIndex) { 1619fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown Log.w(TAG, "Ignoring route descriptor with duplicate id: " 1620fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown + routeDescriptor); 1621c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } else { 1622c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown // 1. Reorder the route within the list. 1623fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown RouteInfo route = provider.mRoutes.get(sourceIndex); 1624fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown Collections.swap(provider.mRoutes, 1625c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown sourceIndex, targetIndex++); 1626c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown // 2. Update the route's contents. 1627c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown int changes = route.updateDescriptor(routeDescriptor); 1628fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown // 3. Unselect route if needed before notifying about changes. 1629fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown unselectRouteIfNeeded(route); 1630fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown // 4. Notify clients about changes. 1631c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if ((changes & RouteInfo.CHANGE_GENERAL) != 0) { 163211417b1cfde8f1749905f2d735623af9214148afJeff Brown if (DEBUG) { 163311417b1cfde8f1749905f2d735623af9214148afJeff Brown Log.d(TAG, "Route changed: " + route); 163411417b1cfde8f1749905f2d735623af9214148afJeff Brown } 1635c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown mCallbackHandler.post( 1636c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown CallbackHandler.MSG_ROUTE_CHANGED, route); 1637c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1638c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if ((changes & RouteInfo.CHANGE_VOLUME) != 0) { 163911417b1cfde8f1749905f2d735623af9214148afJeff Brown if (DEBUG) { 164011417b1cfde8f1749905f2d735623af9214148afJeff Brown Log.d(TAG, "Route volume changed: " + route); 164111417b1cfde8f1749905f2d735623af9214148afJeff Brown } 1642c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown mCallbackHandler.post( 1643c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown CallbackHandler.MSG_ROUTE_VOLUME_CHANGED, route); 1644c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1645c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if ((changes & RouteInfo.CHANGE_PRESENTATION_DISPLAY) != 0) { 164611417b1cfde8f1749905f2d735623af9214148afJeff Brown if (DEBUG) { 164711417b1cfde8f1749905f2d735623af9214148afJeff Brown Log.d(TAG, "Route presentation display changed: " 164811417b1cfde8f1749905f2d735623af9214148afJeff Brown + route); 164911417b1cfde8f1749905f2d735623af9214148afJeff Brown } 1650fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mCallbackHandler.post(CallbackHandler. 1651fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown MSG_ROUTE_PRESENTATION_DISPLAY_CHANGED, route); 1652c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1653c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1654c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1655fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } else { 1656fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown Log.w(TAG, "Ignoring invalid provider descriptor: " + providerDescriptor); 1657c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1658c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1659c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1660c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown // Dispose all remaining routes that do not have matching descriptors. 1661fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown for (int i = provider.mRoutes.size() - 1; i >= targetIndex; i--) { 1662fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown // 1. Delete the route's contents. 1663fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown RouteInfo route = provider.mRoutes.get(i); 1664c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown route.updateDescriptor(null); 1665fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown // 2. Remove the route from the list. 166611417b1cfde8f1749905f2d735623af9214148afJeff Brown mRoutes.remove(route); 1667fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown provider.mRoutes.remove(i); 1668fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown // 3. Unselect route if needed before notifying about removal. 1669fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown unselectRouteIfNeeded(route); 1670fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown // 4. Notify clients about removal. 167111417b1cfde8f1749905f2d735623af9214148afJeff Brown if (DEBUG) { 167211417b1cfde8f1749905f2d735623af9214148afJeff Brown Log.d(TAG, "Route removed: " + route); 167311417b1cfde8f1749905f2d735623af9214148afJeff Brown } 1674fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mCallbackHandler.post(CallbackHandler.MSG_ROUTE_REMOVED, route); 1675c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1676fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 167711417b1cfde8f1749905f2d735623af9214148afJeff Brown // Notify provider changed. 167811417b1cfde8f1749905f2d735623af9214148afJeff Brown if (DEBUG) { 167911417b1cfde8f1749905f2d735623af9214148afJeff Brown Log.d(TAG, "Provider changed: " + provider); 168011417b1cfde8f1749905f2d735623af9214148afJeff Brown } 168111417b1cfde8f1749905f2d735623af9214148afJeff Brown mCallbackHandler.post(CallbackHandler.MSG_PROVIDER_CHANGED, provider); 168211417b1cfde8f1749905f2d735623af9214148afJeff Brown 1683fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown // Choose a new selected route if needed. 1684fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown selectRouteIfNeeded(); 1685c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1686c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1687c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1688fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private void unselectRouteIfNeeded(RouteInfo route) { 1689fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (mDefaultRoute == route && !isRouteSelectable(route)) { 1690c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown Log.i(TAG, "Choosing a new default route because the current one " 1691fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown + "is no longer selectable: " + route); 1692c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown mDefaultRoute = null; 1693c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1694fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (mSelectedRoute == route && !isRouteSelectable(route)) { 1695fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown Log.i(TAG, "Choosing a new selected route because the current one " 1696fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown + "is no longer selectable: " + route); 1697fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown setSelectedRouteInternal(null); 1698fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 1699fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 1700fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 1701fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private void selectRouteIfNeeded() { 1702c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (mDefaultRoute == null && !mRoutes.isEmpty()) { 1703c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown for (RouteInfo route : mRoutes) { 1704c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (isSystemDefaultRoute(route) && isRouteSelectable(route)) { 1705c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown mDefaultRoute = route; 1706c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown break; 1707c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1708c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1709c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1710c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (mSelectedRoute == null) { 1711c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown setSelectedRouteInternal(mDefaultRoute); 1712c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1713c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1714c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1715c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown private boolean isRouteSelectable(RouteInfo route) { 1716c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown // This tests whether the route is still valid and enabled. 1717c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown // The route descriptor field is set to null when the route is removed. 1718c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return route.mDescriptor != null && route.mEnabled; 1719c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1720c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1721c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown private boolean isSystemDefaultRoute(RouteInfo route) { 1722fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return route.getProviderInstance() == mSystemProvider 1723c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown && route.mDescriptorId.equals( 1724c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown SystemMediaRouteProvider.DEFAULT_ROUTE_ID); 1725c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1726c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1727c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown private void setSelectedRouteInternal(RouteInfo route) { 1728c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (mSelectedRoute != route) { 1729c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (mSelectedRoute != null) { 173011417b1cfde8f1749905f2d735623af9214148afJeff Brown if (DEBUG) { 173111417b1cfde8f1749905f2d735623af9214148afJeff Brown Log.d(TAG, "Route unselected: " + mSelectedRoute); 173211417b1cfde8f1749905f2d735623af9214148afJeff Brown } 1733c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown mCallbackHandler.post(CallbackHandler.MSG_ROUTE_UNSELECTED, mSelectedRoute); 1734c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (mSelectedRouteController != null) { 1735129abf73ce9be1bc172b945263c7975ad1a3006fJeff Brown mSelectedRouteController.onUnselect(); 1736129abf73ce9be1bc172b945263c7975ad1a3006fJeff Brown mSelectedRouteController.onRelease(); 1737c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown mSelectedRouteController = null; 1738c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1739c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1740c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1741c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown mSelectedRoute = route; 1742c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1743c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (mSelectedRoute != null) { 1744fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mSelectedRouteController = route.getProviderInstance().onCreateRouteController( 1745c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown route.mDescriptorId); 1746c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (mSelectedRouteController != null) { 1747129abf73ce9be1bc172b945263c7975ad1a3006fJeff Brown mSelectedRouteController.onSelect(); 1748c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 174911417b1cfde8f1749905f2d735623af9214148afJeff Brown if (DEBUG) { 175011417b1cfde8f1749905f2d735623af9214148afJeff Brown Log.d(TAG, "Route selected: " + mSelectedRoute); 175111417b1cfde8f1749905f2d735623af9214148afJeff Brown } 1752c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown mCallbackHandler.post(CallbackHandler.MSG_ROUTE_SELECTED, mSelectedRoute); 1753c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1754c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1755c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1756c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1757c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown @Override 1758c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public RouteInfo getSystemRouteByDescriptorId(String id) { 1759fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown int providerIndex = findProviderInfo(mSystemProvider); 1760c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (providerIndex >= 0) { 1761fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown ProviderInfo provider = mProviders.get(providerIndex); 1762fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown int routeIndex = provider.findRouteByDescriptorId(id); 1763c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (routeIndex >= 0) { 1764fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return provider.mRoutes.get(routeIndex); 1765c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1766c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1767c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return null; 1768c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1769c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1770c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown private final class ProviderCallback extends MediaRouteProvider.Callback { 1771c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown @Override 1772c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public void onDescriptorChanged(MediaRouteProvider provider, 177311417b1cfde8f1749905f2d735623af9214148afJeff Brown MediaRouteProviderDescriptor descriptor) { 1774c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown updateProviderDescriptor(provider, descriptor); 1775c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1776c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1777c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1778c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown private final class CallbackHandler extends Handler { 17799fcedc160282e6620f409ea46bf6728b35d011ddJeff Brown private final ArrayList<CallbackRecord> mTempCallbackRecords = 17809fcedc160282e6620f409ea46bf6728b35d011ddJeff Brown new ArrayList<CallbackRecord>(); 1781c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 178211417b1cfde8f1749905f2d735623af9214148afJeff Brown private static final int MSG_TYPE_MASK = 0xff00; 178311417b1cfde8f1749905f2d735623af9214148afJeff Brown private static final int MSG_TYPE_ROUTE = 0x0100; 178411417b1cfde8f1749905f2d735623af9214148afJeff Brown private static final int MSG_TYPE_PROVIDER = 0x0200; 178511417b1cfde8f1749905f2d735623af9214148afJeff Brown 178611417b1cfde8f1749905f2d735623af9214148afJeff Brown public static final int MSG_ROUTE_ADDED = MSG_TYPE_ROUTE | 1; 178711417b1cfde8f1749905f2d735623af9214148afJeff Brown public static final int MSG_ROUTE_REMOVED = MSG_TYPE_ROUTE | 2; 178811417b1cfde8f1749905f2d735623af9214148afJeff Brown public static final int MSG_ROUTE_CHANGED = MSG_TYPE_ROUTE | 3; 178911417b1cfde8f1749905f2d735623af9214148afJeff Brown public static final int MSG_ROUTE_VOLUME_CHANGED = MSG_TYPE_ROUTE | 4; 179011417b1cfde8f1749905f2d735623af9214148afJeff Brown public static final int MSG_ROUTE_PRESENTATION_DISPLAY_CHANGED = MSG_TYPE_ROUTE | 5; 179111417b1cfde8f1749905f2d735623af9214148afJeff Brown public static final int MSG_ROUTE_SELECTED = MSG_TYPE_ROUTE | 6; 179211417b1cfde8f1749905f2d735623af9214148afJeff Brown public static final int MSG_ROUTE_UNSELECTED = MSG_TYPE_ROUTE | 7; 179311417b1cfde8f1749905f2d735623af9214148afJeff Brown 179411417b1cfde8f1749905f2d735623af9214148afJeff Brown public static final int MSG_PROVIDER_ADDED = MSG_TYPE_PROVIDER | 1; 179511417b1cfde8f1749905f2d735623af9214148afJeff Brown public static final int MSG_PROVIDER_REMOVED = MSG_TYPE_PROVIDER | 2; 179611417b1cfde8f1749905f2d735623af9214148afJeff Brown public static final int MSG_PROVIDER_CHANGED = MSG_TYPE_PROVIDER | 3; 1797c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1798fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public void post(int msg, Object obj) { 1799fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown obtainMessage(msg, obj).sendToTarget(); 1800c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1801c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1802c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown @Override 1803c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public void handleMessage(Message msg) { 1804c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown final int what = msg.what; 1805fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown final Object obj = msg.obj; 1806c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1807c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown // Synchronize state with the system media router. 1808fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown syncWithSystemProvider(what, obj); 1809c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1810c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown // Invoke all registered callbacks. 18119fcedc160282e6620f409ea46bf6728b35d011ddJeff Brown // Build a list of callbacks before invoking them in case callbacks 18129fcedc160282e6620f409ea46bf6728b35d011ddJeff Brown // are added or removed during dispatch. 1813c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown try { 18149fcedc160282e6620f409ea46bf6728b35d011ddJeff Brown for (int i = mRouters.size(); --i >= 0; ) { 18159fcedc160282e6620f409ea46bf6728b35d011ddJeff Brown MediaRouter router = mRouters.get(i).get(); 18169fcedc160282e6620f409ea46bf6728b35d011ddJeff Brown if (router == null) { 18179fcedc160282e6620f409ea46bf6728b35d011ddJeff Brown mRouters.remove(i); 18189fcedc160282e6620f409ea46bf6728b35d011ddJeff Brown } else { 18199fcedc160282e6620f409ea46bf6728b35d011ddJeff Brown mTempCallbackRecords.addAll(router.mCallbackRecords); 1820c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1821c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 18229fcedc160282e6620f409ea46bf6728b35d011ddJeff Brown 18239fcedc160282e6620f409ea46bf6728b35d011ddJeff Brown final int callbackCount = mTempCallbackRecords.size(); 18249fcedc160282e6620f409ea46bf6728b35d011ddJeff Brown for (int i = 0; i < callbackCount; i++) { 18259fcedc160282e6620f409ea46bf6728b35d011ddJeff Brown invokeCallback(mTempCallbackRecords.get(i), what, obj); 18269fcedc160282e6620f409ea46bf6728b35d011ddJeff Brown } 1827c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } finally { 18289fcedc160282e6620f409ea46bf6728b35d011ddJeff Brown mTempCallbackRecords.clear(); 1829c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1830c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1831c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1832fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private void syncWithSystemProvider(int what, Object obj) { 1833c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown switch (what) { 1834c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown case MSG_ROUTE_ADDED: 1835fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mSystemProvider.onSyncRouteAdded((RouteInfo)obj); 1836c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown break; 1837c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown case MSG_ROUTE_REMOVED: 1838fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mSystemProvider.onSyncRouteRemoved((RouteInfo)obj); 1839c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown break; 1840c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown case MSG_ROUTE_CHANGED: 1841fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mSystemProvider.onSyncRouteChanged((RouteInfo)obj); 1842c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown break; 1843c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown case MSG_ROUTE_SELECTED: 1844fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mSystemProvider.onSyncRouteSelected((RouteInfo)obj); 1845c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown break; 1846c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1847c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1848c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 18499fcedc160282e6620f409ea46bf6728b35d011ddJeff Brown private void invokeCallback(CallbackRecord record, int what, Object obj) { 18509fcedc160282e6620f409ea46bf6728b35d011ddJeff Brown final MediaRouter router = record.mRouter; 185111417b1cfde8f1749905f2d735623af9214148afJeff Brown final MediaRouter.Callback callback = record.mCallback; 185211417b1cfde8f1749905f2d735623af9214148afJeff Brown switch (what & MSG_TYPE_MASK) { 185311417b1cfde8f1749905f2d735623af9214148afJeff Brown case MSG_TYPE_ROUTE: { 185411417b1cfde8f1749905f2d735623af9214148afJeff Brown final RouteInfo route = (RouteInfo)obj; 185511417b1cfde8f1749905f2d735623af9214148afJeff Brown if (!record.filterRouteEvent(route)) { 185611417b1cfde8f1749905f2d735623af9214148afJeff Brown break; 185711417b1cfde8f1749905f2d735623af9214148afJeff Brown } 185811417b1cfde8f1749905f2d735623af9214148afJeff Brown switch (what) { 185911417b1cfde8f1749905f2d735623af9214148afJeff Brown case MSG_ROUTE_ADDED: 186011417b1cfde8f1749905f2d735623af9214148afJeff Brown callback.onRouteAdded(router, route); 186111417b1cfde8f1749905f2d735623af9214148afJeff Brown break; 186211417b1cfde8f1749905f2d735623af9214148afJeff Brown case MSG_ROUTE_REMOVED: 186311417b1cfde8f1749905f2d735623af9214148afJeff Brown callback.onRouteRemoved(router, route); 186411417b1cfde8f1749905f2d735623af9214148afJeff Brown break; 186511417b1cfde8f1749905f2d735623af9214148afJeff Brown case MSG_ROUTE_CHANGED: 186611417b1cfde8f1749905f2d735623af9214148afJeff Brown callback.onRouteChanged(router, route); 186711417b1cfde8f1749905f2d735623af9214148afJeff Brown break; 186811417b1cfde8f1749905f2d735623af9214148afJeff Brown case MSG_ROUTE_VOLUME_CHANGED: 186911417b1cfde8f1749905f2d735623af9214148afJeff Brown callback.onRouteVolumeChanged(router, route); 187011417b1cfde8f1749905f2d735623af9214148afJeff Brown break; 187111417b1cfde8f1749905f2d735623af9214148afJeff Brown case MSG_ROUTE_PRESENTATION_DISPLAY_CHANGED: 187211417b1cfde8f1749905f2d735623af9214148afJeff Brown callback.onRoutePresentationDisplayChanged(router, route); 187311417b1cfde8f1749905f2d735623af9214148afJeff Brown break; 187411417b1cfde8f1749905f2d735623af9214148afJeff Brown case MSG_ROUTE_SELECTED: 187511417b1cfde8f1749905f2d735623af9214148afJeff Brown callback.onRouteSelected(router, route); 187611417b1cfde8f1749905f2d735623af9214148afJeff Brown break; 187711417b1cfde8f1749905f2d735623af9214148afJeff Brown case MSG_ROUTE_UNSELECTED: 187811417b1cfde8f1749905f2d735623af9214148afJeff Brown callback.onRouteUnselected(router, route); 187911417b1cfde8f1749905f2d735623af9214148afJeff Brown break; 188011417b1cfde8f1749905f2d735623af9214148afJeff Brown } 1881c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown break; 188211417b1cfde8f1749905f2d735623af9214148afJeff Brown } 188311417b1cfde8f1749905f2d735623af9214148afJeff Brown case MSG_TYPE_PROVIDER: { 188411417b1cfde8f1749905f2d735623af9214148afJeff Brown final ProviderInfo provider = (ProviderInfo)obj; 188511417b1cfde8f1749905f2d735623af9214148afJeff Brown switch (what) { 188611417b1cfde8f1749905f2d735623af9214148afJeff Brown case MSG_PROVIDER_ADDED: 188711417b1cfde8f1749905f2d735623af9214148afJeff Brown callback.onProviderAdded(router, provider); 188811417b1cfde8f1749905f2d735623af9214148afJeff Brown break; 188911417b1cfde8f1749905f2d735623af9214148afJeff Brown case MSG_PROVIDER_REMOVED: 189011417b1cfde8f1749905f2d735623af9214148afJeff Brown callback.onProviderRemoved(router, provider); 189111417b1cfde8f1749905f2d735623af9214148afJeff Brown break; 189211417b1cfde8f1749905f2d735623af9214148afJeff Brown case MSG_PROVIDER_CHANGED: 189311417b1cfde8f1749905f2d735623af9214148afJeff Brown callback.onProviderChanged(router, provider); 189411417b1cfde8f1749905f2d735623af9214148afJeff Brown break; 189511417b1cfde8f1749905f2d735623af9214148afJeff Brown } 189611417b1cfde8f1749905f2d735623af9214148afJeff Brown } 1897c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1898c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1899c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1900c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1901c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown} 1902