MediaRouter.java revision 2ef36d857302c5cd738c7c8bdec53d31feebebba
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 34c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brownimport java.util.ArrayList; 35c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brownimport java.util.Collections; 36c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brownimport java.util.List; 37c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brownimport java.util.WeakHashMap; 38c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brownimport java.util.concurrent.CopyOnWriteArrayList; 39c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 40c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown/** 41c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * MediaRouter allows applications to control the routing of media channels 42c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * and streams from the current device to external speakers and destination devices. 43c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * <p> 44c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * A MediaRouter instance is retrieved through {@link #getInstance}. Applications 45c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * can query the media router about the currently selected route and its capabilities 46c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * to determine how to send content to the route's destination. Applications can 47c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * also {@link RouteInfo#sendControlRequest send control requests} to the route 48c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * to ask the route's destination to perform certain remote control functions 49fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * such as playing media. 50c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * </p><p> 51c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * See also {@link MediaRouteProvider} for information on how an application 52c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * can publish new media routes to the media router. 53c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * </p><p> 54c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * The media router API is not thread-safe; all interactions with it must be 55c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * done from the main thread of the process. 56c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * </p> 57c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 58c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brownpublic final class MediaRouter { 59c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown private static final String TAG = "MediaRouter"; 6011417b1cfde8f1749905f2d735623af9214148afJeff Brown private static final boolean DEBUG = false; 61c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 62c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown // Maintains global media router state for the process. 63c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown // This field is initialized in MediaRouter.getInstance() before any 64c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown // MediaRouter objects are instantiated so it is guaranteed to be 65c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown // valid whenever any instance method is invoked. 66c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown static GlobalMediaRouter sGlobal; 67c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 68c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown // Context-bound state of the media router. 69c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown final Context mContext; 7011417b1cfde8f1749905f2d735623af9214148afJeff Brown final CopyOnWriteArrayList<CallbackRecord> mCallbackRecords = 7111417b1cfde8f1749905f2d735623af9214148afJeff Brown new CopyOnWriteArrayList<CallbackRecord>(); 7211417b1cfde8f1749905f2d735623af9214148afJeff Brown 7311417b1cfde8f1749905f2d735623af9214148afJeff Brown /** 7411417b1cfde8f1749905f2d735623af9214148afJeff Brown * Flag for {@link #addCallback}: Actively scan for routes while this callback 7511417b1cfde8f1749905f2d735623af9214148afJeff Brown * is registered. 7611417b1cfde8f1749905f2d735623af9214148afJeff Brown * <p> 7711417b1cfde8f1749905f2d735623af9214148afJeff Brown * When this flag is specified, the media router will actively scan for new 7811417b1cfde8f1749905f2d735623af9214148afJeff Brown * routes. Certain routes, such as wifi display routes, may not be discoverable 7911417b1cfde8f1749905f2d735623af9214148afJeff Brown * except when actively scanning. This flag is typically used when the route picker 8011417b1cfde8f1749905f2d735623af9214148afJeff Brown * dialog has been opened by the user to ensure that the route information is 8111417b1cfde8f1749905f2d735623af9214148afJeff Brown * up to date. 8211417b1cfde8f1749905f2d735623af9214148afJeff Brown * </p><p> 8311417b1cfde8f1749905f2d735623af9214148afJeff Brown * Active scanning may consume a significant amount of power and may have intrusive 8411417b1cfde8f1749905f2d735623af9214148afJeff Brown * effects on wireless connectivity. Therefore it is important that active scanning 8511417b1cfde8f1749905f2d735623af9214148afJeff Brown * only be requested when it is actually needed to satisfy a user request to 8611417b1cfde8f1749905f2d735623af9214148afJeff Brown * discover and select a new route. 8711417b1cfde8f1749905f2d735623af9214148afJeff Brown * </p> 8811417b1cfde8f1749905f2d735623af9214148afJeff Brown */ 8911417b1cfde8f1749905f2d735623af9214148afJeff Brown public static final int CALLBACK_FLAG_ACTIVE_SCAN = 1 << 0; 9011417b1cfde8f1749905f2d735623af9214148afJeff Brown 9111417b1cfde8f1749905f2d735623af9214148afJeff Brown /** 9211417b1cfde8f1749905f2d735623af9214148afJeff Brown * Flag for {@link #addCallback}: Do not filter route events. 9311417b1cfde8f1749905f2d735623af9214148afJeff Brown * <p> 9411417b1cfde8f1749905f2d735623af9214148afJeff Brown * When this flag is specified, the callback will be invoked for events that affect any 9511417b1cfde8f1749905f2d735623af9214148afJeff Brown * route event if they do not match the callback's associated media route selector. 9611417b1cfde8f1749905f2d735623af9214148afJeff Brown * </p> 9711417b1cfde8f1749905f2d735623af9214148afJeff Brown */ 9811417b1cfde8f1749905f2d735623af9214148afJeff Brown public static final int CALLBACK_FLAG_UNFILTERED_EVENTS = 1 << 1; 9911417b1cfde8f1749905f2d735623af9214148afJeff Brown 10011417b1cfde8f1749905f2d735623af9214148afJeff Brown /** 10111417b1cfde8f1749905f2d735623af9214148afJeff Brown * Flag for {@link #isRouteAvailable}: Ignore the default route. 10211417b1cfde8f1749905f2d735623af9214148afJeff Brown * <p> 10311417b1cfde8f1749905f2d735623af9214148afJeff Brown * This flag is used to determine whether a matching non-default route is available. 10411417b1cfde8f1749905f2d735623af9214148afJeff Brown * This constraint may be used to decide whether to offer the route chooser dialog 10511417b1cfde8f1749905f2d735623af9214148afJeff Brown * to the user. There is no point offering the chooser if there are no 10611417b1cfde8f1749905f2d735623af9214148afJeff Brown * non-default choices. 10711417b1cfde8f1749905f2d735623af9214148afJeff Brown * </p> 10811417b1cfde8f1749905f2d735623af9214148afJeff Brown */ 10911417b1cfde8f1749905f2d735623af9214148afJeff Brown public static final int AVAILABILITY_FLAG_IGNORE_DEFAULT_ROUTE = 1 << 0; 11011417b1cfde8f1749905f2d735623af9214148afJeff Brown 11111417b1cfde8f1749905f2d735623af9214148afJeff Brown /** 11211417b1cfde8f1749905f2d735623af9214148afJeff Brown * Flag for {@link #isRouteAvailable}: Consider whether matching routes 11311417b1cfde8f1749905f2d735623af9214148afJeff Brown * might be discovered if an active scan were performed. 11411417b1cfde8f1749905f2d735623af9214148afJeff Brown * <p> 11511417b1cfde8f1749905f2d735623af9214148afJeff Brown * If no existing routes match the route selector, then this flag is used to 11611417b1cfde8f1749905f2d735623af9214148afJeff Brown * determine whether to consider whether any route providers that require active 11711417b1cfde8f1749905f2d735623af9214148afJeff Brown * scans might discover matching routes if an active scan were actually performed. 11811417b1cfde8f1749905f2d735623af9214148afJeff Brown * </p><p> 11911417b1cfde8f1749905f2d735623af9214148afJeff Brown * This flag may be used to decide whether to offer the route chooser dialog to the user. 12011417b1cfde8f1749905f2d735623af9214148afJeff Brown * When the dialog is opened, an active scan will be performed which may cause 12111417b1cfde8f1749905f2d735623af9214148afJeff Brown * additional routes to be discovered by any providers that require active scans. 12211417b1cfde8f1749905f2d735623af9214148afJeff Brown * </p> 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 /** 131c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Gets an instance of the media router service from the context. 132c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 133c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public static MediaRouter getInstance(Context context) { 134c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (context == null) { 135c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown throw new IllegalArgumentException("context must not be null"); 136c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 137c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown checkCallingThread(); 138c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 139c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (sGlobal == null) { 140c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown sGlobal = new GlobalMediaRouter(context.getApplicationContext()); 141fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown sGlobal.start(); 142c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 143c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return sGlobal.getRouter(context); 144c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 145c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 146c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 147fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * Gets information about the {@link MediaRouter.RouteInfo routes} currently known to 148fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * this media router. 149c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 150c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public List<RouteInfo> getRoutes() { 151c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown checkCallingThread(); 152c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return sGlobal.getRoutes(); 153c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 154c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 155c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 156fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * Gets information about the {@link MediaRouter.ProviderInfo route providers} 157fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * currently known to this media router. 158fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown */ 159fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public List<ProviderInfo> getProviders() { 160fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown checkCallingThread(); 161fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return sGlobal.getProviders(); 162fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 163fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 164fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown /** 165c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Gets the default route for playing media content on the system. 166c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * <p> 167c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * The system always provides a default route. 168c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * </p> 169c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 170c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @return The default route, which is guaranteed to never be null. 171c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 172c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public RouteInfo getDefaultRoute() { 173c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown checkCallingThread(); 174c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return sGlobal.getDefaultRoute(); 175c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 176c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 177c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 178c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Gets the currently selected route. 179c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * <p> 180c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * The application should examine the route's 181fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * {@link RouteInfo#getControlFilters media control intent filters} to assess the 182c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * capabilities of the route before attempting to use it. 183c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * </p> 184c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 185c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * <h3>Example</h3> 186c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * <pre> 187c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * public boolean playMovie() { 188c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * MediaRouter mediaRouter = MediaRouter.getInstance(context); 189c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * MediaRouter.RouteInfo route = mediaRouter.getSelectedRoute(); 190c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 191c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * // First try using the remote playback interface, if supported. 192c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * if (route.supportsControlCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK)) { 193c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * // The route supports remote playback. 194c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * // Try to send it the Uri of the movie to play. 195c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Intent intent = new Intent(MediaControlIntent.ACTION_PLAY); 196c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * intent.addCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK); 197c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * intent.setDataAndType("http://example.com/videos/movie.mp4", "video/mp4"); 198fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * if (route.supportsControlRequest(intent)) { 199fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * route.sendControlRequest(intent, null); 200fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * return true; // sent the request to play the movie 201c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * } 202c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * } 203c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 204c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * // If remote playback was not possible, then play locally. 205c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * if (route.supportsControlCategory(MediaControlIntent.CATEGORY_LIVE_VIDEO)) { 206c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * // The route supports live video streaming. 207c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * // Prepare to play content locally in a window or in a presentation. 208c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * return playMovieInWindow(); 209c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * } 210c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 211c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * // Neither interface is supported, so we can't play the movie to this route. 212c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * return false; 213c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * } 214c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * </pre> 215c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 216c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @return The selected route, which is guaranteed to never be null. 217c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 218fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * @see RouteInfo#getControlFilters 219c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @see RouteInfo#supportsControlCategory 220c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @see RouteInfo#supportsControlRequest 221c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 222c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public RouteInfo getSelectedRoute() { 223c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown checkCallingThread(); 224c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return sGlobal.getSelectedRoute(); 225c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 226c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 227c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 22828520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown * Returns the selected route if it matches the specified selector, otherwise 22928520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown * selects the default route and returns it. 23028520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown * 23128520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown * @param selector The selector to match. 23228520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown * @return The previously selected route if it matched the selector, otherwise the 23328520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown * newly selected default route which is guaranteed to never be null. 23428520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown * 23511417b1cfde8f1749905f2d735623af9214148afJeff Brown * @see MediaRouteSelector 23628520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown * @see RouteInfo#matchesSelector 23728520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown * @see RouteInfo#isDefault 23828520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown */ 23911417b1cfde8f1749905f2d735623af9214148afJeff Brown public RouteInfo updateSelectedRoute(MediaRouteSelector selector) { 24028520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown if (selector == null) { 24128520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown throw new IllegalArgumentException("selector must not be null"); 24228520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown } 24328520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown checkCallingThread(); 24428520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown 24511417b1cfde8f1749905f2d735623af9214148afJeff Brown if (DEBUG) { 24611417b1cfde8f1749905f2d735623af9214148afJeff Brown Log.d(TAG, "updateSelectedRoute: " + selector); 24711417b1cfde8f1749905f2d735623af9214148afJeff Brown } 24828520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown RouteInfo route = sGlobal.getSelectedRoute(); 24911417b1cfde8f1749905f2d735623af9214148afJeff Brown if (!route.isDefault() && !route.matchesSelector(selector)) { 25028520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown route = sGlobal.getDefaultRoute(); 25128520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown sGlobal.selectRoute(route); 25228520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown } 25328520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown return route; 25428520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown } 25528520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown 25628520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown /** 257c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Selects the specified route. 258c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 259c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @param route The route to select. 260c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 261c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public void selectRoute(RouteInfo route) { 262c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (route == null) { 263c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown throw new IllegalArgumentException("route must not be null"); 264c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 265c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown checkCallingThread(); 266c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 26711417b1cfde8f1749905f2d735623af9214148afJeff Brown if (DEBUG) { 26811417b1cfde8f1749905f2d735623af9214148afJeff Brown Log.d(TAG, "selectRoute: " + route); 26911417b1cfde8f1749905f2d735623af9214148afJeff Brown } 270c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown sGlobal.selectRoute(route); 271c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 272c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 273c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 27411417b1cfde8f1749905f2d735623af9214148afJeff Brown * Returns true if there is a route that matches the specified selector 27511417b1cfde8f1749905f2d735623af9214148afJeff Brown * or, depending on the specified availability flags, if it is possible to discover one. 27611417b1cfde8f1749905f2d735623af9214148afJeff Brown * <p> 27711417b1cfde8f1749905f2d735623af9214148afJeff Brown * This method first considers whether there are any available 27811417b1cfde8f1749905f2d735623af9214148afJeff Brown * routes that match the selector regardless of whether they are enabled or 27911417b1cfde8f1749905f2d735623af9214148afJeff Brown * disabled. If not and the {@link #AVAILABILITY_FLAG_CONSIDER_ACTIVE_SCAN} flag 28011417b1cfde8f1749905f2d735623af9214148afJeff Brown * was specifies, then it considers whether any of the route providers 28111417b1cfde8f1749905f2d735623af9214148afJeff Brown * could discover a matching route if an active scan were performed. 28211417b1cfde8f1749905f2d735623af9214148afJeff Brown * </p> 283c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 28411417b1cfde8f1749905f2d735623af9214148afJeff Brown * @param selector The selector to match. 28511417b1cfde8f1749905f2d735623af9214148afJeff Brown * @param flags Flags to control the determination of whether a route may be available. 28611417b1cfde8f1749905f2d735623af9214148afJeff Brown * May be zero or a combination of 28711417b1cfde8f1749905f2d735623af9214148afJeff Brown * {@link #AVAILABILITY_FLAG_IGNORE_DEFAULT_ROUTE} and 28811417b1cfde8f1749905f2d735623af9214148afJeff Brown * {@link #AVAILABILITY_FLAG_CONSIDER_ACTIVE_SCAN}. 28911417b1cfde8f1749905f2d735623af9214148afJeff Brown * @return True if a matching route may be available. 290c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 29111417b1cfde8f1749905f2d735623af9214148afJeff Brown public boolean isRouteAvailable(MediaRouteSelector selector, int flags) { 29211417b1cfde8f1749905f2d735623af9214148afJeff Brown if (selector == null) { 29311417b1cfde8f1749905f2d735623af9214148afJeff Brown throw new IllegalArgumentException("selector must not be null"); 294c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 295c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown checkCallingThread(); 296c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 29711417b1cfde8f1749905f2d735623af9214148afJeff Brown return sGlobal.isRouteAvailable(selector, flags); 298c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 299c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 300c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 30111417b1cfde8f1749905f2d735623af9214148afJeff Brown * Registers a callback to discover routes that match the selector and to receive 30211417b1cfde8f1749905f2d735623af9214148afJeff Brown * events when they change. 30311417b1cfde8f1749905f2d735623af9214148afJeff Brown * <p> 30411417b1cfde8f1749905f2d735623af9214148afJeff Brown * This is a convenience method that has the same effect as calling 30511417b1cfde8f1749905f2d735623af9214148afJeff Brown * {@link #addCallback(MediaRouteSelector, Callback, int)} without flags. 30611417b1cfde8f1749905f2d735623af9214148afJeff Brown * </p> 307c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 30811417b1cfde8f1749905f2d735623af9214148afJeff Brown * @param selector A route selector that indicates the kinds of routes that the 30911417b1cfde8f1749905f2d735623af9214148afJeff Brown * callback would like to discover. 31011417b1cfde8f1749905f2d735623af9214148afJeff Brown * @param callback The callback to add. 31111417b1cfde8f1749905f2d735623af9214148afJeff Brown * @see #removeCallback 312c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 31311417b1cfde8f1749905f2d735623af9214148afJeff Brown public void addCallback(MediaRouteSelector selector, Callback callback) { 31411417b1cfde8f1749905f2d735623af9214148afJeff Brown addCallback(selector, callback, 0); 315c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 316c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 317c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 31811417b1cfde8f1749905f2d735623af9214148afJeff Brown * Registers a callback to discover routes that match the selector and to receive 31911417b1cfde8f1749905f2d735623af9214148afJeff Brown * events when they change. 32028520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown * <p> 32111417b1cfde8f1749905f2d735623af9214148afJeff Brown * The selector describes the kinds of routes that the application wants to 32211417b1cfde8f1749905f2d735623af9214148afJeff Brown * discover. For example, if the application wants to use 32311417b1cfde8f1749905f2d735623af9214148afJeff Brown * live audio routes then it should include the 32411417b1cfde8f1749905f2d735623af9214148afJeff Brown * {@link MediaControlIntent#CATEGORY_LIVE_AUDIO live audio media control intent category} 32511417b1cfde8f1749905f2d735623af9214148afJeff Brown * in its selector when it adds a callback to the media router. 32611417b1cfde8f1749905f2d735623af9214148afJeff Brown * The selector may include any number of categories. 32728520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown * </p><p> 32811417b1cfde8f1749905f2d735623af9214148afJeff Brown * If the callback has already been registered, then the selector is added to 32911417b1cfde8f1749905f2d735623af9214148afJeff Brown * the set of selectors being monitored by the callback. 33011417b1cfde8f1749905f2d735623af9214148afJeff Brown * </p><p> 33111417b1cfde8f1749905f2d735623af9214148afJeff Brown * By default, the callback will only be invoked for events that affect routes 33211417b1cfde8f1749905f2d735623af9214148afJeff Brown * that match the specified selector. Event filtering may be disabled by specifying 33311417b1cfde8f1749905f2d735623af9214148afJeff Brown * the {@link #CALLBACK_FLAG_UNFILTERED_EVENTS} flag when the callback is registered. 33428520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown * </p> 33528520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown * 33628520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown * <h3>Example</h3> 33728520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown * <pre> 33811417b1cfde8f1749905f2d735623af9214148afJeff Brown * public class MyActivity extends Activity { 33911417b1cfde8f1749905f2d735623af9214148afJeff Brown * private MediaRouter mRouter; 34011417b1cfde8f1749905f2d735623af9214148afJeff Brown * private MediaRouter.Callback mCallback; 34111417b1cfde8f1749905f2d735623af9214148afJeff Brown * private MediaRouteSelector mSelector; 34228520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown * 34311417b1cfde8f1749905f2d735623af9214148afJeff Brown * protected void onCreate(Bundle savedInstanceState) { 34411417b1cfde8f1749905f2d735623af9214148afJeff Brown * super.onCreate(savedInstanceState); 34511417b1cfde8f1749905f2d735623af9214148afJeff Brown * 34611417b1cfde8f1749905f2d735623af9214148afJeff Brown * mRouter = Mediarouter.getInstance(this); 34711417b1cfde8f1749905f2d735623af9214148afJeff Brown * mCallback = new MyCallback(); 34811417b1cfde8f1749905f2d735623af9214148afJeff Brown * mSelector = new MediaRouteSelector.Builder() 34911417b1cfde8f1749905f2d735623af9214148afJeff Brown * .addControlCategory(MediaControlIntent.CATEGORY_LIVE_AUDIO) 35011417b1cfde8f1749905f2d735623af9214148afJeff Brown * .addControlCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK) 35111417b1cfde8f1749905f2d735623af9214148afJeff Brown * .build(); 35228520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown * } 35328520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown * 35411417b1cfde8f1749905f2d735623af9214148afJeff Brown * // Add the callback on resume to tell the media router what kinds of routes 35511417b1cfde8f1749905f2d735623af9214148afJeff Brown * // the application is interested in so that it can try to discover suitable ones. 35611417b1cfde8f1749905f2d735623af9214148afJeff Brown * public void onResume() { 35711417b1cfde8f1749905f2d735623af9214148afJeff Brown * super.onResume(); 35811417b1cfde8f1749905f2d735623af9214148afJeff Brown * 35911417b1cfde8f1749905f2d735623af9214148afJeff Brown * mediaRouter.addCallback(mSelector, mCallback); 36011417b1cfde8f1749905f2d735623af9214148afJeff Brown * 36111417b1cfde8f1749905f2d735623af9214148afJeff Brown * MediaRouter.RouteInfo route = mediaRouter.updateSelectedRoute(mSelector); 36211417b1cfde8f1749905f2d735623af9214148afJeff Brown * // do something with the route... 36311417b1cfde8f1749905f2d735623af9214148afJeff Brown * } 36411417b1cfde8f1749905f2d735623af9214148afJeff Brown * 36511417b1cfde8f1749905f2d735623af9214148afJeff Brown * // Remove the selector on pause to tell the media router that it no longer 36611417b1cfde8f1749905f2d735623af9214148afJeff Brown * // needs to invest effort trying to discover routes of these kinds for now. 36711417b1cfde8f1749905f2d735623af9214148afJeff Brown * public void onPause() { 36811417b1cfde8f1749905f2d735623af9214148afJeff Brown * super.onPause(); 36911417b1cfde8f1749905f2d735623af9214148afJeff Brown * 37011417b1cfde8f1749905f2d735623af9214148afJeff Brown * mediaRouter.removeCallback(mCallback); 37111417b1cfde8f1749905f2d735623af9214148afJeff Brown * } 37211417b1cfde8f1749905f2d735623af9214148afJeff Brown * 37311417b1cfde8f1749905f2d735623af9214148afJeff Brown * private final class MyCallback extends MediaRouter.Callback { 37411417b1cfde8f1749905f2d735623af9214148afJeff Brown * // Implement callback methods as needed. 37528520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown * } 37628520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown * } 37728520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown * </pre> 37828520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown * 37911417b1cfde8f1749905f2d735623af9214148afJeff Brown * @param selector A route selector that indicates the kinds of routes that the 38011417b1cfde8f1749905f2d735623af9214148afJeff Brown * callback would like to discover. 38111417b1cfde8f1749905f2d735623af9214148afJeff Brown * @param callback The callback to add. 38211417b1cfde8f1749905f2d735623af9214148afJeff Brown * @param flags Flags to control the behavior of the callback. 38311417b1cfde8f1749905f2d735623af9214148afJeff Brown * May be zero or a combination of {@link #CALLBACK_FLAG_ACTIVE_SCAN} and 38411417b1cfde8f1749905f2d735623af9214148afJeff Brown * {@link #CALLBACK_FLAG_UNFILTERED_EVENTS}. 38511417b1cfde8f1749905f2d735623af9214148afJeff Brown * @see #removeCallback 38628520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown */ 38711417b1cfde8f1749905f2d735623af9214148afJeff Brown public void addCallback(MediaRouteSelector selector, Callback callback, int flags) { 38828520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown if (selector == null) { 38928520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown throw new IllegalArgumentException("selector must not be null"); 39028520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown } 39111417b1cfde8f1749905f2d735623af9214148afJeff Brown if (callback == null) { 39211417b1cfde8f1749905f2d735623af9214148afJeff Brown throw new IllegalArgumentException("callback must not be null"); 39311417b1cfde8f1749905f2d735623af9214148afJeff Brown } 39428520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown checkCallingThread(); 39528520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown 39611417b1cfde8f1749905f2d735623af9214148afJeff Brown if (DEBUG) { 39711417b1cfde8f1749905f2d735623af9214148afJeff Brown Log.d(TAG, "addCallback: selector=" + selector 39811417b1cfde8f1749905f2d735623af9214148afJeff Brown + ", callback=" + callback + ", flags=" + Integer.toHexString(flags)); 39911417b1cfde8f1749905f2d735623af9214148afJeff Brown } 40011417b1cfde8f1749905f2d735623af9214148afJeff Brown 40111417b1cfde8f1749905f2d735623af9214148afJeff Brown CallbackRecord record; 40211417b1cfde8f1749905f2d735623af9214148afJeff Brown int index = findCallbackRecord(callback); 40311417b1cfde8f1749905f2d735623af9214148afJeff Brown if (index < 0) { 40411417b1cfde8f1749905f2d735623af9214148afJeff Brown record = new CallbackRecord(callback); 40511417b1cfde8f1749905f2d735623af9214148afJeff Brown mCallbackRecords.add(record); 40611417b1cfde8f1749905f2d735623af9214148afJeff Brown } else { 40711417b1cfde8f1749905f2d735623af9214148afJeff Brown record = mCallbackRecords.get(index); 40811417b1cfde8f1749905f2d735623af9214148afJeff Brown } 40911417b1cfde8f1749905f2d735623af9214148afJeff Brown boolean updateNeeded = false; 41011417b1cfde8f1749905f2d735623af9214148afJeff Brown if ((flags & ~record.mFlags) != 0) { 41111417b1cfde8f1749905f2d735623af9214148afJeff Brown record.mFlags |= flags; 41211417b1cfde8f1749905f2d735623af9214148afJeff Brown updateNeeded = true; 41311417b1cfde8f1749905f2d735623af9214148afJeff Brown } 41411417b1cfde8f1749905f2d735623af9214148afJeff Brown if (!record.mSelector.contains(selector)) { 41511417b1cfde8f1749905f2d735623af9214148afJeff Brown record.mSelector = new MediaRouteSelector.Builder(record.mSelector) 41611417b1cfde8f1749905f2d735623af9214148afJeff Brown .addSelector(selector) 41711417b1cfde8f1749905f2d735623af9214148afJeff Brown .build(); 41811417b1cfde8f1749905f2d735623af9214148afJeff Brown updateNeeded = true; 41911417b1cfde8f1749905f2d735623af9214148afJeff Brown } 42011417b1cfde8f1749905f2d735623af9214148afJeff Brown if (updateNeeded) { 42111417b1cfde8f1749905f2d735623af9214148afJeff Brown sGlobal.updateDiscoveryRequest(); 42228520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown } 42328520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown } 42428520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown 42528520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown /** 42611417b1cfde8f1749905f2d735623af9214148afJeff Brown * Removes the specified callback. It will no longer receive events about 42711417b1cfde8f1749905f2d735623af9214148afJeff Brown * changes to media routes. 42828520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown * 42911417b1cfde8f1749905f2d735623af9214148afJeff Brown * @param callback The callback to remove. 43011417b1cfde8f1749905f2d735623af9214148afJeff Brown * @see #addCallback 43128520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown */ 43211417b1cfde8f1749905f2d735623af9214148afJeff Brown public void removeCallback(Callback callback) { 43311417b1cfde8f1749905f2d735623af9214148afJeff Brown if (callback == null) { 43411417b1cfde8f1749905f2d735623af9214148afJeff Brown throw new IllegalArgumentException("callback must not be null"); 43528520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown } 43628520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown checkCallingThread(); 43728520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown 43811417b1cfde8f1749905f2d735623af9214148afJeff Brown if (DEBUG) { 43911417b1cfde8f1749905f2d735623af9214148afJeff Brown Log.d(TAG, "removeCallback: callback=" + callback); 44011417b1cfde8f1749905f2d735623af9214148afJeff Brown } 44111417b1cfde8f1749905f2d735623af9214148afJeff Brown 44211417b1cfde8f1749905f2d735623af9214148afJeff Brown int index = findCallbackRecord(callback); 44311417b1cfde8f1749905f2d735623af9214148afJeff Brown if (index >= 0) { 44411417b1cfde8f1749905f2d735623af9214148afJeff Brown mCallbackRecords.remove(index); 44511417b1cfde8f1749905f2d735623af9214148afJeff Brown sGlobal.updateDiscoveryRequest(); 44628520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown } 44728520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown } 44828520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown 44911417b1cfde8f1749905f2d735623af9214148afJeff Brown private int findCallbackRecord(Callback callback) { 45011417b1cfde8f1749905f2d735623af9214148afJeff Brown final int count = mCallbackRecords.size(); 45111417b1cfde8f1749905f2d735623af9214148afJeff Brown for (int i = 0; i < count; i++) { 45211417b1cfde8f1749905f2d735623af9214148afJeff Brown if (mCallbackRecords.get(i).mCallback == callback) { 45311417b1cfde8f1749905f2d735623af9214148afJeff Brown return i; 45411417b1cfde8f1749905f2d735623af9214148afJeff Brown } 45511417b1cfde8f1749905f2d735623af9214148afJeff Brown } 45611417b1cfde8f1749905f2d735623af9214148afJeff Brown return -1; 45711417b1cfde8f1749905f2d735623af9214148afJeff Brown } 45811417b1cfde8f1749905f2d735623af9214148afJeff Brown 45928520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown /** 460c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Registers a media route provider globally for this application process. 461c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 462fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * @param providerInstance The media route provider instance to add. 463c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 464c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @see MediaRouteProvider 46528520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown * @see #removeCallback 466c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 467fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public void addProvider(MediaRouteProvider providerInstance) { 468fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (providerInstance == null) { 469fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown throw new IllegalArgumentException("providerInstance must not be null"); 470c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 471c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown checkCallingThread(); 472c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 47311417b1cfde8f1749905f2d735623af9214148afJeff Brown if (DEBUG) { 47411417b1cfde8f1749905f2d735623af9214148afJeff Brown Log.d(TAG, "addProvider: " + providerInstance); 47511417b1cfde8f1749905f2d735623af9214148afJeff Brown } 476fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown sGlobal.addProvider(providerInstance); 477c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 478c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 479c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 480c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Unregisters a media route provider globally for this application process. 481c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 482fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * @param providerInstance The media route provider instance to remove. 483c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 484c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @see MediaRouteProvider 48528520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown * @see #addCallback 486c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 487fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public void removeProvider(MediaRouteProvider providerInstance) { 488fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (providerInstance == null) { 489fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown throw new IllegalArgumentException("providerInstance must not be null"); 490c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 491c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown checkCallingThread(); 492c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 49311417b1cfde8f1749905f2d735623af9214148afJeff Brown if (DEBUG) { 49411417b1cfde8f1749905f2d735623af9214148afJeff Brown Log.d(TAG, "removeProvider: " + providerInstance); 49528520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown } 49611417b1cfde8f1749905f2d735623af9214148afJeff Brown sGlobal.removeProvider(providerInstance); 49728520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown } 49828520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown 49928520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown /** 500c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Ensures that calls into the media router are on the correct thread. 501c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * It pays to be a little paranoid when global state invariants are at risk. 502c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 503c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown static void checkCallingThread() { 504c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (Looper.myLooper() != Looper.getMainLooper()) { 505c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown throw new IllegalStateException("The media router service must only be " 506c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown + "accessed on the application's main thread."); 507c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 508c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 509c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 510c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown static <T> boolean equal(T a, T b) { 511c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return a == b || (a != null && b != null && a.equals(b)); 512c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 513c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 514c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 515c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Provides information about a media route. 516c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * <p> 517fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * Each media route has a list of {@link MediaControlIntent media control} 518fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * {@link #getControlFilters intent filters} that describe the capabilities of the 519c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * route and the manner in which it is used and controlled. 520c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * </p> 521c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 522c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public static final class RouteInfo { 523fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private final ProviderInfo mProvider; 524c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown private final String mDescriptorId; 525c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown private String mName; 526d63957d28aaabcec588b8cde12eac16414783aebJeff Brown private String mDescription; 527c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown private boolean mEnabled; 52811417b1cfde8f1749905f2d735623af9214148afJeff Brown private boolean mConnecting; 529fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private final ArrayList<IntentFilter> mControlFilters = new ArrayList<IntentFilter>(); 530c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown private int mPlaybackType; 531c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown private int mPlaybackStream; 532c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown private int mVolumeHandling; 533c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown private int mVolume; 534c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown private int mVolumeMax; 535c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown private Display mPresentationDisplay; 536c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown private int mPresentationDisplayId = -1; 537c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown private Bundle mExtras; 53811417b1cfde8f1749905f2d735623af9214148afJeff Brown private MediaRouteDescriptor mDescriptor; 539c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 540c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 541c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * The default playback type, "local", indicating the presentation of the media 542c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * is happening on the same device (e.g. a phone, a tablet) as where it is 543c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * controlled from. 544c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 545c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @see #getPlaybackType 546c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 547c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public static final int PLAYBACK_TYPE_LOCAL = 0; 548c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 549c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 550c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * A playback type indicating the presentation of the media is happening on 551c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * a different device (i.e. the remote device) than where it is controlled from. 552c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 553c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @see #getPlaybackType 554c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 555c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public static final int PLAYBACK_TYPE_REMOTE = 1; 556c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 557c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 558c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Playback information indicating the playback volume is fixed, i.e. it cannot be 559c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * controlled from this object. An example of fixed playback volume is a remote player, 560c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * playing over HDMI where the user prefers to control the volume on the HDMI sink, rather 561c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * than attenuate at the source. 562c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 563c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @see #getVolumeHandling 564c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 565c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public static final int PLAYBACK_VOLUME_FIXED = 0; 566c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 567c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 568c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Playback information indicating the playback volume is variable and can be controlled 569c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * from this object. 570c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 571c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @see #getVolumeHandling 572c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 573c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public static final int PLAYBACK_VOLUME_VARIABLE = 1; 574c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 575c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown static final int CHANGE_GENERAL = 1 << 0; 576c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown static final int CHANGE_VOLUME = 1 << 1; 577c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown static final int CHANGE_PRESENTATION_DISPLAY = 1 << 2; 578c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 579fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown RouteInfo(ProviderInfo provider, String descriptorId) { 580fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mProvider = provider; 581c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown mDescriptorId = descriptorId; 582c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 583c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 584fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown /** 585fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * Gets information about the provider of this media route. 586fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown */ 587fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public ProviderInfo getProvider() { 588fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return mProvider; 589c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 590c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 591c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 592d63957d28aaabcec588b8cde12eac16414783aebJeff Brown * Gets the user-visible name of the route. 593d63957d28aaabcec588b8cde12eac16414783aebJeff Brown * <p> 594d63957d28aaabcec588b8cde12eac16414783aebJeff Brown * The route name identifies the destination represented by the route. 595d63957d28aaabcec588b8cde12eac16414783aebJeff Brown * It may be a user-supplied name, an alias, or device serial number. 596d63957d28aaabcec588b8cde12eac16414783aebJeff Brown * </p> 597c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 598d63957d28aaabcec588b8cde12eac16414783aebJeff Brown * @return The user-visible name of a media route. This is the string presented 599c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * to users who may select this as the active route. 600c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 601c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public String getName() { 602c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return mName; 603c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 604c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 605c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 606d63957d28aaabcec588b8cde12eac16414783aebJeff Brown * Gets the user-visible description of the route. 607d63957d28aaabcec588b8cde12eac16414783aebJeff Brown * <p> 608d63957d28aaabcec588b8cde12eac16414783aebJeff Brown * The route description describes the kind of destination represented by the route. 609d63957d28aaabcec588b8cde12eac16414783aebJeff Brown * It may be a user-supplied string, a model number or brand of device. 610d63957d28aaabcec588b8cde12eac16414783aebJeff Brown * </p> 611c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 612d63957d28aaabcec588b8cde12eac16414783aebJeff Brown * @return The description of the route, or null if none. 613c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 614d63957d28aaabcec588b8cde12eac16414783aebJeff Brown public String getDescription() { 615d63957d28aaabcec588b8cde12eac16414783aebJeff Brown return mDescription; 616c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 617c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 618c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 619c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Returns true if this route is enabled and may be selected. 620c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 62111417b1cfde8f1749905f2d735623af9214148afJeff Brown * @return True if this route is enabled. 622c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 623c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public boolean isEnabled() { 624c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return mEnabled; 625c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 626c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 627c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 62811417b1cfde8f1749905f2d735623af9214148afJeff Brown * Returns true if the route is in the process of connecting and is not 62911417b1cfde8f1749905f2d735623af9214148afJeff Brown * yet ready for use. 63011417b1cfde8f1749905f2d735623af9214148afJeff Brown * 63111417b1cfde8f1749905f2d735623af9214148afJeff Brown * @return True if this route is in the process of connecting. 63211417b1cfde8f1749905f2d735623af9214148afJeff Brown */ 63311417b1cfde8f1749905f2d735623af9214148afJeff Brown public boolean isConnecting() { 63411417b1cfde8f1749905f2d735623af9214148afJeff Brown return mConnecting; 63511417b1cfde8f1749905f2d735623af9214148afJeff Brown } 63611417b1cfde8f1749905f2d735623af9214148afJeff Brown 63711417b1cfde8f1749905f2d735623af9214148afJeff Brown /** 638fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * Returns true if this route is currently selected. 639c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 64011417b1cfde8f1749905f2d735623af9214148afJeff Brown * @return True if this route is currently selected. 641fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * 642fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * @see MediaRouter#getSelectedRoute 643fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown */ 644fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public boolean isSelected() { 645fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown checkCallingThread(); 646fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return sGlobal.getSelectedRoute() == this; 647fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 648fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 649fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown /** 650fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * Returns true if this route is the default route. 651fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * 65211417b1cfde8f1749905f2d735623af9214148afJeff Brown * @return True if this route is the default route. 653fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * 654fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * @see MediaRouter#getDefaultRoute 655fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown */ 656fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public boolean isDefault() { 657fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown checkCallingThread(); 658fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return sGlobal.getDefaultRoute() == this; 659fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 660fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 661fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown /** 662fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * Gets a list of {@link MediaControlIntent media control intent} filters that 663fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * describe the capabilities of this route and the media control actions that 664fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * it supports. 665fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * 666fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * @return A list of intent filters that specifies the media control intents that 667fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * this route supports. 668c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 669c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @see MediaControlIntent 670c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @see #supportsControlCategory 671c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @see #supportsControlRequest 672c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 673fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public List<IntentFilter> getControlFilters() { 674fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return mControlFilters; 675c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 676c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 677c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 67828520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown * Returns true if the route supports at least one of the capabilities 67928520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown * described by a media route selector. 68028520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown * 68128520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown * @param selector The selector that specifies the capabilities to check. 68228520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown * @return True if the route supports at least one of the capabilities 68328520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown * described in the media route selector. 68428520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown */ 68511417b1cfde8f1749905f2d735623af9214148afJeff Brown public boolean matchesSelector(MediaRouteSelector selector) { 68628520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown if (selector == null) { 68728520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown throw new IllegalArgumentException("selector must not be null"); 68828520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown } 68928520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown checkCallingThread(); 69011417b1cfde8f1749905f2d735623af9214148afJeff Brown return selector.matchesControlFilters(mControlFilters); 69128520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown } 69228520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown 69328520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown /** 694c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Returns true if the route supports the specified 695c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * {@link MediaControlIntent media control} category. 696c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * <p> 697c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Media control categories describe the capabilities of this route 698c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * such as whether it supports live audio streaming or remote playback. 699c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * </p> 700c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 701c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @param category A {@link MediaControlIntent media control} category 702c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * such as {@link MediaControlIntent#CATEGORY_LIVE_AUDIO}, 703c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * {@link MediaControlIntent#CATEGORY_LIVE_VIDEO}, 704fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * {@link MediaControlIntent#CATEGORY_REMOTE_PLAYBACK}, or a provider-defined 705c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * media control category. 70628520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown * @return True if the route supports the specified intent category. 707c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 708c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @see MediaControlIntent 709fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * @see #getControlFilters 710c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 711c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public boolean supportsControlCategory(String category) { 712c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (category == null) { 713c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown throw new IllegalArgumentException("category must not be null"); 714c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 715fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown checkCallingThread(); 716c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 717fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown int count = mControlFilters.size(); 718fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown for (int i = 0; i < count; i++) { 719fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (mControlFilters.get(i).hasCategory(category)) { 720fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return true; 721fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 722fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 723fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return false; 724c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 725c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 726c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 727c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Returns true if the route supports the specified 728c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * {@link MediaControlIntent media control} request. 729c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * <p> 730c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Media control requests are used to request the route to perform 73143f79f79a5117550a7dfedf9c65124afd163ea43Jeff Brown * actions such as starting remote playback of a media item. 732c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * </p> 733c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 734c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @param intent A {@link MediaControlIntent media control intent}. 735c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @return True if the route can handle the specified intent. 736c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 737c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @see MediaControlIntent 738fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * @see #getControlFilters 739c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 740c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public boolean supportsControlRequest(Intent intent) { 741c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (intent == null) { 742c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown throw new IllegalArgumentException("intent must not be null"); 743c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 744c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown checkCallingThread(); 745c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 746c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown ContentResolver contentResolver = sGlobal.getContentResolver(); 747fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown int count = mControlFilters.size(); 748fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown for (int i = 0; i < count; i++) { 749fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (mControlFilters.get(i).match(contentResolver, intent, true, TAG) >= 0) { 750fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return true; 751fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 752fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 753fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return false; 754c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 755c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 756c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 757c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Sends a {@link MediaControlIntent media control} request to be performed 758c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * asynchronously by the route's destination. 759c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * <p> 760c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Media control requests are used to request the route to perform 76143f79f79a5117550a7dfedf9c65124afd163ea43Jeff Brown * actions such as starting remote playback of a media item. 762c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * </p><p> 763fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * This function may only be called on a selected route. Control requests 764fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * sent to unselected routes will fail. 765c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * </p> 766c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 767c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @param intent A {@link MediaControlIntent media control intent}. 768c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @param callback A {@link ControlRequestCallback} to invoke with the result 769c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * of the request, or null if no result is required. 770c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 771c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @see MediaControlIntent 772c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 773fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public void sendControlRequest(Intent intent, ControlRequestCallback callback) { 774c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (intent == null) { 775c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown throw new IllegalArgumentException("intent must not be null"); 776c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 777c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown checkCallingThread(); 778c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 779fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown sGlobal.sendControlRequest(this, intent, callback); 780c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 781c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 782c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 783c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Gets the type of playback associated with this route. 784c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 785c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @return The type of playback associated with this route: {@link #PLAYBACK_TYPE_LOCAL} 786c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * or {@link #PLAYBACK_TYPE_REMOTE}. 787c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 788c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public int getPlaybackType() { 789c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return mPlaybackType; 790c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 791c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 792c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 793350ba6e4a1b5ec28721a098e50eaf6a508eb28f0Jeff Brown * Gets the audio stream over which the playback associated with this route is performed. 794c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 795c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @return The stream over which the playback associated with this route is performed. 796c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 797c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public int getPlaybackStream() { 798c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return mPlaybackStream; 799c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 800c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 801c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 802c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Gets information about how volume is handled on the route. 803c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 804c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @return How volume is handled on the route: {@link #PLAYBACK_VOLUME_FIXED} 805c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * or {@link #PLAYBACK_VOLUME_VARIABLE}. 806c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 807c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public int getVolumeHandling() { 808c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return mVolumeHandling; 809c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 810c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 811c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 812c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Gets the current volume for this route. Depending on the route, this may only 813c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * be valid if the route is currently selected. 814c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 815c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @return The volume at which the playback associated with this route is performed. 816c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 817c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public int getVolume() { 818c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return mVolume; 819c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 820c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 821c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 822c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Gets the maximum volume at which the playback associated with this route is performed. 823c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 824c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @return The maximum volume at which the playback associated with 825c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * this route is performed. 826c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 827c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public int getVolumeMax() { 828c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return mVolumeMax; 829c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 830c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 831c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 832c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Requests a volume change for this route asynchronously. 833c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * <p> 834c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * This function may only be called on a selected route. It will have 835c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * no effect if the route is currently unselected. 836c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * </p> 837c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 838c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @param volume The new volume value between 0 and {@link #getVolumeMax}. 839c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 840c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public void requestSetVolume(int volume) { 841c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown checkCallingThread(); 842c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown sGlobal.requestSetVolume(this, Math.min(mVolumeMax, Math.max(0, volume))); 843c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 844c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 845c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 846c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Requests an incremental volume update for this route asynchronously. 847c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * <p> 848c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * This function may only be called on a selected route. It will have 849c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * no effect if the route is currently unselected. 850c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * </p> 851c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 852c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @param delta The delta to add to the current volume. 853c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 854c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public void requestUpdateVolume(int delta) { 855c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown checkCallingThread(); 856c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (delta != 0) { 857c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown sGlobal.requestUpdateVolume(this, delta); 858c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 859c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 860c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 861c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 862c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Gets the {@link Display} that should be used by the application to show 863c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * a {@link android.app.Presentation} on an external display when this route is selected. 864c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Depending on the route, this may only be valid if the route is currently 865c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * selected. 866c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * <p> 867c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * The preferred presentation display may change independently of the route 868c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * being selected or unselected. For example, the presentation display 869c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * of the default system route may change when an external HDMI display is connected 870c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * or disconnected even though the route itself has not changed. 871c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * </p><p> 872c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * This method may return null if there is no external display associated with 873c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * the route or if the display is not ready to show UI yet. 874c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * </p><p> 875c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * The application should listen for changes to the presentation display 876c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * using the {@link Callback#onRoutePresentationDisplayChanged} callback and 877c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * show or dismiss its {@link android.app.Presentation} accordingly when the display 878c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * becomes available or is removed. 879c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * </p><p> 880c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * This method only makes sense for 881c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * {@link MediaControlIntent#CATEGORY_LIVE_VIDEO live video} routes. 882c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * </p> 883c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 884c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @return The preferred presentation display to use when this route is 885c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * selected or null if none. 886c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 887c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @see MediaControlIntent#CATEGORY_LIVE_VIDEO 888c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @see android.app.Presentation 889c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 890c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public Display getPresentationDisplay() { 891fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown checkCallingThread(); 892c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (mPresentationDisplayId >= 0 && mPresentationDisplay == null) { 893c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown mPresentationDisplay = sGlobal.getDisplay(mPresentationDisplayId); 894c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 895c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return mPresentationDisplay; 896c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 897c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 898c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 899c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Gets a collection of extra properties about this route that were supplied 900c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * by its media route provider, or null if none. 901c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 902c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public Bundle getExtras() { 903c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return mExtras; 904c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 905c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 906fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown /** 907fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * Selects this media route. 908fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown */ 909fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public void select() { 910fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown checkCallingThread(); 911fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown sGlobal.selectRoute(this); 912fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 913fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 914c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown @Override 915c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public String toString() { 916c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return "MediaRouter.RouteInfo{ name=" + mName 917d63957d28aaabcec588b8cde12eac16414783aebJeff Brown + ", description=" + mDescription 918c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown + ", enabled=" + mEnabled 91911417b1cfde8f1749905f2d735623af9214148afJeff Brown + ", connecting=" + mConnecting 920c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown + ", playbackType=" + mPlaybackType 921c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown + ", playbackStream=" + mPlaybackStream 922c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown + ", volumeHandling=" + mVolumeHandling 923c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown + ", volume=" + mVolume 924c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown + ", volumeMax=" + mVolumeMax 925c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown + ", presentationDisplayId=" + mPresentationDisplayId 926c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown + ", extras=" + mExtras 927fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown + ", providerPackageName=" + mProvider.getPackageName() 928fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown + " }"; 929fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 930fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 93111417b1cfde8f1749905f2d735623af9214148afJeff Brown int updateDescriptor(MediaRouteDescriptor descriptor) { 932fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown int changes = 0; 933fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (mDescriptor != descriptor) { 934fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mDescriptor = descriptor; 935fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (descriptor != null) { 936fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (!equal(mName, descriptor.getName())) { 937fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mName = descriptor.getName(); 938fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown changes |= CHANGE_GENERAL; 939fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 940d63957d28aaabcec588b8cde12eac16414783aebJeff Brown if (!equal(mDescription, descriptor.getDescription())) { 941d63957d28aaabcec588b8cde12eac16414783aebJeff Brown mDescription = descriptor.getDescription(); 942fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown changes |= CHANGE_GENERAL; 943fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 944fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (mEnabled != descriptor.isEnabled()) { 945fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mEnabled = descriptor.isEnabled(); 946fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown changes |= CHANGE_GENERAL; 947fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 94811417b1cfde8f1749905f2d735623af9214148afJeff Brown if (mConnecting != descriptor.isConnecting()) { 94911417b1cfde8f1749905f2d735623af9214148afJeff Brown mConnecting = descriptor.isConnecting(); 95011417b1cfde8f1749905f2d735623af9214148afJeff Brown changes |= CHANGE_GENERAL; 95111417b1cfde8f1749905f2d735623af9214148afJeff Brown } 95211417b1cfde8f1749905f2d735623af9214148afJeff Brown if (!mControlFilters.equals(descriptor.getControlFilters())) { 953fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mControlFilters.clear(); 95411417b1cfde8f1749905f2d735623af9214148afJeff Brown mControlFilters.addAll(descriptor.getControlFilters()); 955fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown changes |= CHANGE_GENERAL; 956fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 957fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (mPlaybackType != descriptor.getPlaybackType()) { 958fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mPlaybackType = descriptor.getPlaybackType(); 959fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown changes |= CHANGE_GENERAL; 960fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 961fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (mPlaybackStream != descriptor.getPlaybackStream()) { 962fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mPlaybackStream = descriptor.getPlaybackStream(); 963fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown changes |= CHANGE_GENERAL; 964fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 965fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (mVolumeHandling != descriptor.getVolumeHandling()) { 966fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mVolumeHandling = descriptor.getVolumeHandling(); 967fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown changes |= CHANGE_GENERAL | CHANGE_VOLUME; 968fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 969fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (mVolume != descriptor.getVolume()) { 970fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mVolume = descriptor.getVolume(); 971fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown changes |= CHANGE_GENERAL | CHANGE_VOLUME; 972fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 973fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (mVolumeMax != descriptor.getVolumeMax()) { 974fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mVolumeMax = descriptor.getVolumeMax(); 975fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown changes |= CHANGE_GENERAL | CHANGE_VOLUME; 976fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 977fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (mPresentationDisplayId != descriptor.getPresentationDisplayId()) { 978fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mPresentationDisplayId = descriptor.getPresentationDisplayId(); 979fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mPresentationDisplay = null; 980fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown changes |= CHANGE_GENERAL | CHANGE_PRESENTATION_DISPLAY; 981fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 982fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (!equal(mExtras, descriptor.getExtras())) { 983fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mExtras = descriptor.getExtras(); 984fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown changes |= CHANGE_GENERAL; 985fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 986fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 987fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 988fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return changes; 989fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 990fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 991fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown String getDescriptorId() { 992fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return mDescriptorId; 993fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 994fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 995fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown MediaRouteProvider getProviderInstance() { 996fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return mProvider.getProviderInstance(); 997fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 998fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 999fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 1000fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown /** 1001fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * Provides information about a media route provider. 1002fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * <p> 1003fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * This object may be used to determine which media route provider has 1004fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * published a particular route. 1005fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * </p> 1006fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown */ 1007fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public static final class ProviderInfo { 1008fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private final MediaRouteProvider mProviderInstance; 1009fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private final ArrayList<RouteInfo> mRoutes = new ArrayList<RouteInfo>(); 101011417b1cfde8f1749905f2d735623af9214148afJeff Brown private final ArrayList<IntentFilter> mDiscoverableControlFilters = 101111417b1cfde8f1749905f2d735623af9214148afJeff Brown new ArrayList<IntentFilter>(); 1012fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 1013fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private final ProviderMetadata mMetadata; 101411417b1cfde8f1749905f2d735623af9214148afJeff Brown private MediaRouteProviderDescriptor mDescriptor; 1015fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private Resources mResources; 1016fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private boolean mResourcesNotAvailable; 1017fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 1018fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown ProviderInfo(MediaRouteProvider provider) { 1019fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mProviderInstance = provider; 1020fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mMetadata = provider.getMetadata(); 1021fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 1022fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 1023fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown /** 1024fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * Gets the provider's underlying {@link MediaRouteProvider} instance. 1025fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown */ 1026fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public MediaRouteProvider getProviderInstance() { 1027fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown checkCallingThread(); 1028fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return mProviderInstance; 1029fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 1030fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 1031fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown /** 1032fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * Gets the package name of the media route provider service. 1033fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown */ 1034fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public String getPackageName() { 1035fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return mMetadata.getPackageName(); 1036fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 1037fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 1038fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown /** 1039fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * Gets the {@link MediaRouter.RouteInfo routes} published by this route provider. 1040fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown */ 1041fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public List<RouteInfo> getRoutes() { 1042fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown checkCallingThread(); 1043fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return mRoutes; 1044fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 1045fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 104628520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown /** 104728520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown * Returns true if the provider requires active scans to discover routes. 104811417b1cfde8f1749905f2d735623af9214148afJeff Brown * <p> 104911417b1cfde8f1749905f2d735623af9214148afJeff Brown * To provide the best user experience, a media route provider should passively 105011417b1cfde8f1749905f2d735623af9214148afJeff Brown * discover and publish changes to route descriptors in the background. 105111417b1cfde8f1749905f2d735623af9214148afJeff Brown * However, for some providers, scanning for routes may use a significant 105211417b1cfde8f1749905f2d735623af9214148afJeff Brown * amount of power or may interfere with wireless network connectivity. 105311417b1cfde8f1749905f2d735623af9214148afJeff Brown * If this is the case, then the provider will indicate that it requires 105411417b1cfde8f1749905f2d735623af9214148afJeff Brown * active scans to discover routes by setting this flag. Active scans 105511417b1cfde8f1749905f2d735623af9214148afJeff Brown * will be performed when the user opens the route chooser dialog. 105611417b1cfde8f1749905f2d735623af9214148afJeff Brown * </p> 105728520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown */ 105828520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown public boolean isActiveScanRequired() { 105928520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown checkCallingThread(); 106028520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown return mDescriptor != null && mDescriptor.isActiveScanRequired(); 106128520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown } 106228520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown 106311417b1cfde8f1749905f2d735623af9214148afJeff Brown /** 106411417b1cfde8f1749905f2d735623af9214148afJeff Brown * Gets a list of {@link MediaControlIntent media route control filters} that 106511417b1cfde8f1749905f2d735623af9214148afJeff Brown * describe the union of capabilities of all routes that this provider can 106611417b1cfde8f1749905f2d735623af9214148afJeff Brown * possibly discover. 106711417b1cfde8f1749905f2d735623af9214148afJeff Brown * <p> 106811417b1cfde8f1749905f2d735623af9214148afJeff Brown * Because a route provider may not know what to look for until an 106911417b1cfde8f1749905f2d735623af9214148afJeff Brown * application actually asks for it, the contents of the discoverable control 107011417b1cfde8f1749905f2d735623af9214148afJeff Brown * filter list may change depending on the route selectors that applications have 107111417b1cfde8f1749905f2d735623af9214148afJeff Brown * actually specified when {@link MediaRouter#addCallback registering callbacks} 107211417b1cfde8f1749905f2d735623af9214148afJeff Brown * on the media router to discover routes. 107311417b1cfde8f1749905f2d735623af9214148afJeff Brown * </p> 107411417b1cfde8f1749905f2d735623af9214148afJeff Brown */ 107511417b1cfde8f1749905f2d735623af9214148afJeff Brown public List<IntentFilter> getDiscoverableControlFilters() { 107611417b1cfde8f1749905f2d735623af9214148afJeff Brown checkCallingThread(); 107711417b1cfde8f1749905f2d735623af9214148afJeff Brown return mDiscoverableControlFilters; 107811417b1cfde8f1749905f2d735623af9214148afJeff Brown } 107911417b1cfde8f1749905f2d735623af9214148afJeff Brown 1080fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown Resources getResources() { 1081fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (mResources == null && !mResourcesNotAvailable) { 1082fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown String packageName = getPackageName(); 1083fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown Context context = sGlobal.getProviderContext(packageName); 1084fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (context != null) { 1085fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mResources = context.getResources(); 1086fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } else { 1087fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown Log.w(TAG, "Unable to obtain resources for route provider package: " 1088fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown + packageName); 1089fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mResourcesNotAvailable = true; 1090fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 1091fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 1092fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return mResources; 1093fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 1094fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 109511417b1cfde8f1749905f2d735623af9214148afJeff Brown boolean updateDescriptor(MediaRouteProviderDescriptor descriptor) { 1096fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (mDescriptor != descriptor) { 1097fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mDescriptor = descriptor; 10982ef36d857302c5cd738c7c8bdec53d31feebebbaJeff Brown if (descriptor != null) { 10992ef36d857302c5cd738c7c8bdec53d31feebebbaJeff Brown if (!mDiscoverableControlFilters.equals( 11002ef36d857302c5cd738c7c8bdec53d31feebebbaJeff Brown descriptor.getDiscoverableControlFilters())) { 11012ef36d857302c5cd738c7c8bdec53d31feebebbaJeff Brown mDiscoverableControlFilters.clear(); 11022ef36d857302c5cd738c7c8bdec53d31feebebbaJeff Brown mDiscoverableControlFilters.addAll(descriptor.getDiscoverableControlFilters()); 11032ef36d857302c5cd738c7c8bdec53d31feebebbaJeff Brown } 110411417b1cfde8f1749905f2d735623af9214148afJeff Brown } 1105fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return true; 1106fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 1107fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return false; 1108fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 1109fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 1110fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown int findRouteByDescriptorId(String id) { 1111fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown final int count = mRoutes.size(); 1112fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown for (int i = 0; i < count; i++) { 1113fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (mRoutes.get(i).mDescriptorId.equals(id)) { 1114fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return i; 1115fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 1116fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 1117fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return -1; 1118fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 1119fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 1120fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown @Override 1121fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public String toString() { 1122fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return "MediaRouter.RouteProviderInfo{ packageName=" + getPackageName() 112311417b1cfde8f1749905f2d735623af9214148afJeff Brown + ", isActiveScanRequired=" + isActiveScanRequired() 1124c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown + " }"; 1125c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1126c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1127c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1128c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 1129c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Interface for receiving events about media routing changes. 1130c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * All methods of this interface will be called from the application's main thread. 1131c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * <p> 1132c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * A Callback will only receive events relevant to routes that the callback 113311417b1cfde8f1749905f2d735623af9214148afJeff Brown * was registered for unless the {@link MediaRouter#CALLBACK_FLAG_UNFILTERED_EVENTS} 113411417b1cfde8f1749905f2d735623af9214148afJeff Brown * flag was specified in {@link MediaRouter#addCallback(MediaRouteSelector, Callback, int)}. 1135c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * </p> 1136c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 113711417b1cfde8f1749905f2d735623af9214148afJeff Brown * @see MediaRouter#addCallback(MediaRouteSelector, Callback, int) 1138c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @see MediaRouter#removeCallback(Callback) 1139c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 1140c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public static abstract class Callback { 1141c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 1142fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * Called when the supplied media route becomes selected as the active route. 1143c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 1144fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * @param router The media router reporting the event. 1145c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @param route The route that has been selected. 1146c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 1147c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public void onRouteSelected(MediaRouter router, RouteInfo route) { 1148c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1149c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1150c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 1151fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * Called when the supplied media route becomes unselected as the active route. 1152c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 1153fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * @param router The media router reporting the event. 1154c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @param route The route that has been unselected. 1155c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 1156c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public void onRouteUnselected(MediaRouter router, RouteInfo route) { 1157c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1158c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1159c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 1160fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * Called when a media route has been added. 1161c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 1162fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * @param router The media router reporting the event. 1163c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @param route The route that has become available for use. 1164c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 1165c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public void onRouteAdded(MediaRouter router, RouteInfo route) { 1166c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1167c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1168c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 1169fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * Called when a media route has been removed. 1170c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 1171fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * @param router The media router reporting the event. 1172c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @param route The route that has been removed from availability. 1173c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 1174c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public void onRouteRemoved(MediaRouter router, RouteInfo route) { 1175c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1176c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1177c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 1178fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * Called when a property of the indicated media route has changed. 1179c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 1180fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * @param router The media router reporting the event. 1181c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @param route The route that was changed. 1182c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 1183c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public void onRouteChanged(MediaRouter router, RouteInfo route) { 1184c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1185c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1186c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 1187fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * Called when a media route's volume changes. 1188c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 1189fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * @param router The media router reporting the event. 1190c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @param route The route whose volume changed. 1191c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 1192c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public void onRouteVolumeChanged(MediaRouter router, RouteInfo route) { 1193c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1194c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1195c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 1196fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * Called when a media route's presentation display changes. 1197c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * <p> 1198c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * This method is called whenever the route's presentation display becomes 1199fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * available, is removed or has changes to some of its properties (such as its size). 1200c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * </p> 1201c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 1202fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * @param router The media router reporting the event. 1203c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @param route The route whose presentation display changed. 1204c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 1205c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @see RouteInfo#getPresentationDisplay() 1206c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 1207c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public void onRoutePresentationDisplayChanged(MediaRouter router, RouteInfo route) { 1208c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1209fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 1210fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown /** 1211fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * Called when a media route provider has been added. 1212fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * 1213fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * @param router The media router reporting the event. 1214fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * @param provider The provider that has become available for use. 1215fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown */ 1216fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public void onProviderAdded(MediaRouter router, ProviderInfo provider) { 1217fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 1218fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 1219fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown /** 1220fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * Called when a media route provider has been removed. 1221fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * 1222fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * @param router The media router reporting the event. 1223fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * @param provider The provider that has been removed from availability. 1224fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown */ 1225fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public void onProviderRemoved(MediaRouter router, ProviderInfo provider) { 1226fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 122711417b1cfde8f1749905f2d735623af9214148afJeff Brown 122811417b1cfde8f1749905f2d735623af9214148afJeff Brown /** 122911417b1cfde8f1749905f2d735623af9214148afJeff Brown * Called when a property of the indicated media route provider has changed. 123011417b1cfde8f1749905f2d735623af9214148afJeff Brown * 123111417b1cfde8f1749905f2d735623af9214148afJeff Brown * @param router The media router reporting the event. 123211417b1cfde8f1749905f2d735623af9214148afJeff Brown * @param provider The provider that was changed. 123311417b1cfde8f1749905f2d735623af9214148afJeff Brown */ 123411417b1cfde8f1749905f2d735623af9214148afJeff Brown public void onProviderChanged(MediaRouter router, ProviderInfo provider) { 123511417b1cfde8f1749905f2d735623af9214148afJeff Brown } 1236c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1237c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1238c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 1239c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Callback which is invoked with the result of a media control request. 1240c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 1241c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @see RouteInfo#sendControlRequest 1242c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 1243fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public static abstract class ControlRequestCallback { 1244c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 1245fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * Result code: The media control action succeeded. 1246c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 1247fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public static final int REQUEST_SUCCEEDED = 0; 1248c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1249c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 1250c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Result code: The media control action failed. 1251c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 1252c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public static final int REQUEST_FAILED = -1; 1253c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1254c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 1255c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Called with the result of the media control request. 1256c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 1257fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * @param result The result code: {@link #REQUEST_SUCCEEDED}, or {@link #REQUEST_FAILED}. 1258c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @param data Additional result data. Contents depend on the media control action. 1259c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 1260c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public void onResult(int result, Bundle data) { 1261c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1262c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1263c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 126411417b1cfde8f1749905f2d735623af9214148afJeff Brown private static final class CallbackRecord { 126511417b1cfde8f1749905f2d735623af9214148afJeff Brown public final Callback mCallback; 126611417b1cfde8f1749905f2d735623af9214148afJeff Brown public MediaRouteSelector mSelector; 126711417b1cfde8f1749905f2d735623af9214148afJeff Brown public int mFlags; 126811417b1cfde8f1749905f2d735623af9214148afJeff Brown 126911417b1cfde8f1749905f2d735623af9214148afJeff Brown public CallbackRecord(Callback callback) { 127011417b1cfde8f1749905f2d735623af9214148afJeff Brown mCallback = callback; 127111417b1cfde8f1749905f2d735623af9214148afJeff Brown mSelector = MediaRouteSelector.EMPTY; 127211417b1cfde8f1749905f2d735623af9214148afJeff Brown } 127311417b1cfde8f1749905f2d735623af9214148afJeff Brown 127411417b1cfde8f1749905f2d735623af9214148afJeff Brown public boolean filterRouteEvent(RouteInfo route) { 127511417b1cfde8f1749905f2d735623af9214148afJeff Brown return (mFlags & CALLBACK_FLAG_UNFILTERED_EVENTS) != 0 127611417b1cfde8f1749905f2d735623af9214148afJeff Brown || route.matchesSelector(mSelector); 127711417b1cfde8f1749905f2d735623af9214148afJeff Brown } 127811417b1cfde8f1749905f2d735623af9214148afJeff Brown } 127911417b1cfde8f1749905f2d735623af9214148afJeff Brown 1280c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 1281c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Global state for the media router. 1282c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * <p> 1283c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Media routes and media route providers are global to the process; their 1284c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * state and the bulk of the media router implementation lives here. 1285c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * </p> 1286c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 1287c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown private static final class GlobalMediaRouter implements SystemMediaRouteProvider.SyncCallback { 1288c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown private final Context mApplicationContext; 1289fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private final MediaRouter mApplicationRouter; 1290c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown private final WeakHashMap<Context, MediaRouter> mRouters = 1291c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown new WeakHashMap<Context, MediaRouter>(); 1292c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown private final ArrayList<RouteInfo> mRoutes = new ArrayList<RouteInfo>(); 1293fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private final ArrayList<ProviderInfo> mProviders = 1294fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown new ArrayList<ProviderInfo>(); 1295c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown private final ProviderCallback mProviderCallback = new ProviderCallback(); 1296c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown private final CallbackHandler mCallbackHandler = new CallbackHandler(); 1297c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown private final DisplayManagerCompat mDisplayManager; 1298c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown private final SystemMediaRouteProvider mSystemProvider; 1299c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1300fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private RegisteredMediaRouteProviderWatcher mRegisteredProviderWatcher; 1301c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown private RouteInfo mDefaultRoute; 1302c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown private RouteInfo mSelectedRoute; 1303c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown private MediaRouteProvider.RouteController mSelectedRouteController; 130411417b1cfde8f1749905f2d735623af9214148afJeff Brown private MediaRouteDiscoveryRequest mDiscoveryRequest; 1305c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1306c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown GlobalMediaRouter(Context applicationContext) { 1307c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown mApplicationContext = applicationContext; 1308c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown mDisplayManager = DisplayManagerCompat.getInstance(applicationContext); 1309fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mApplicationRouter = getRouter(applicationContext); 1310fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 1311fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown // Add the system media route provider for interoperating with 1312fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown // the framework media router. This one is special and receives 1313fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown // synchronization messages from the media router. 1314c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown mSystemProvider = SystemMediaRouteProvider.obtain(applicationContext, this); 1315fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown addProvider(mSystemProvider); 1316fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 1317fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 1318fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public void start() { 1319fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown // Start watching for routes published by registered media route 1320fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown // provider services. 1321fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mRegisteredProviderWatcher = new RegisteredMediaRouteProviderWatcher( 1322fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mApplicationContext, mApplicationRouter); 1323fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mRegisteredProviderWatcher.start(); 1324c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1325c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1326c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public MediaRouter getRouter(Context context) { 1327c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown MediaRouter router = mRouters.get(context); 1328c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (router == null) { 1329c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown router = new MediaRouter(context); 1330c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown mRouters.put(context, router); 1331c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1332c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return router; 1333c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1334c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1335c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public ContentResolver getContentResolver() { 1336c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return mApplicationContext.getContentResolver(); 1337c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1338c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1339fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public Context getProviderContext(String packageName) { 1340fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (packageName.equals(SystemMediaRouteProvider.PACKAGE_NAME)) { 1341fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return mApplicationContext; 1342fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 1343fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown try { 1344fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return mApplicationContext.createPackageContext( 1345fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown packageName, Context.CONTEXT_RESTRICTED); 1346fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } catch (NameNotFoundException ex) { 1347fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return null; 1348fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 1349fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 1350fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 1351c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public Display getDisplay(int displayId) { 1352c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return mDisplayManager.getDisplay(displayId); 1353c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1354c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1355fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public void sendControlRequest(RouteInfo route, 1356c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown Intent intent, ControlRequestCallback callback) { 1357c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (route == mSelectedRoute && mSelectedRouteController != null) { 1358129abf73ce9be1bc172b945263c7975ad1a3006fJeff Brown if (mSelectedRouteController.onControlRequest(intent, callback)) { 1359fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return; 1360fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 1361fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 1362fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (callback != null) { 1363fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown callback.onResult(ControlRequestCallback.REQUEST_FAILED, null); 1364c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1365c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1366c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1367c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public void requestSetVolume(RouteInfo route, int volume) { 1368c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (route == mSelectedRoute && mSelectedRouteController != null) { 1369129abf73ce9be1bc172b945263c7975ad1a3006fJeff Brown mSelectedRouteController.onSetVolume(volume); 1370c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1371c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1372c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1373c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public void requestUpdateVolume(RouteInfo route, int delta) { 1374c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (route == mSelectedRoute && mSelectedRouteController != null) { 1375129abf73ce9be1bc172b945263c7975ad1a3006fJeff Brown mSelectedRouteController.onUpdateVolume(delta); 1376c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1377c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1378c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1379c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public List<RouteInfo> getRoutes() { 1380c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return mRoutes; 1381c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1382c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1383fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public List<ProviderInfo> getProviders() { 1384fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return mProviders; 1385fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 1386fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 1387c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public RouteInfo getDefaultRoute() { 1388c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (mDefaultRoute == null) { 1389c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown // This should never happen once the media router has been fully 1390c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown // initialized but it is good to check for the error in case there 1391c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown // is a bug in provider initialization. 1392c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown throw new IllegalStateException("There is no default route. " 1393c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown + "The media router has not yet been fully initialized."); 1394c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1395c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return mDefaultRoute; 1396c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1397c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1398c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public RouteInfo getSelectedRoute() { 1399c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (mSelectedRoute == null) { 1400c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown // This should never happen once the media router has been fully 1401c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown // initialized but it is good to check for the error in case there 1402c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown // is a bug in provider initialization. 1403c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown throw new IllegalStateException("There is no currently selected route. " 1404c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown + "The media router has not yet been fully initialized."); 1405c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1406c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return mSelectedRoute; 1407c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1408c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1409c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public void selectRoute(RouteInfo route) { 1410c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (!mRoutes.contains(route)) { 1411c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown Log.w(TAG, "Ignoring attempt to select removed route: " + route); 1412c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return; 1413c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1414c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (!route.mEnabled) { 1415c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown Log.w(TAG, "Ignoring attempt to select disabled route: " + route); 1416c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return; 1417c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1418c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1419c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown setSelectedRouteInternal(route); 1420c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1421c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 142211417b1cfde8f1749905f2d735623af9214148afJeff Brown public boolean isRouteAvailable(MediaRouteSelector selector, int flags) { 142311417b1cfde8f1749905f2d735623af9214148afJeff Brown // Check whether any existing routes match the selector. 142411417b1cfde8f1749905f2d735623af9214148afJeff Brown final int routeCount = mRoutes.size(); 142511417b1cfde8f1749905f2d735623af9214148afJeff Brown for (int i = 0; i < routeCount; i++) { 142611417b1cfde8f1749905f2d735623af9214148afJeff Brown RouteInfo route = mRoutes.get(i); 142711417b1cfde8f1749905f2d735623af9214148afJeff Brown if ((flags & AVAILABILITY_FLAG_IGNORE_DEFAULT_ROUTE) != 0 142811417b1cfde8f1749905f2d735623af9214148afJeff Brown && route.isDefault()) { 142911417b1cfde8f1749905f2d735623af9214148afJeff Brown continue; 143011417b1cfde8f1749905f2d735623af9214148afJeff Brown } 143111417b1cfde8f1749905f2d735623af9214148afJeff Brown if (route.matchesSelector(selector)) { 143211417b1cfde8f1749905f2d735623af9214148afJeff Brown return true; 143311417b1cfde8f1749905f2d735623af9214148afJeff Brown } 143411417b1cfde8f1749905f2d735623af9214148afJeff Brown } 143511417b1cfde8f1749905f2d735623af9214148afJeff Brown 143611417b1cfde8f1749905f2d735623af9214148afJeff Brown // Check whether any provider could possibly discover a matching route 143711417b1cfde8f1749905f2d735623af9214148afJeff Brown // if a required active scan were performed. 143811417b1cfde8f1749905f2d735623af9214148afJeff Brown if ((flags & AVAILABILITY_FLAG_CONSIDER_ACTIVE_SCAN) != 0) { 143911417b1cfde8f1749905f2d735623af9214148afJeff Brown final int providerCount = mProviders.size(); 144011417b1cfde8f1749905f2d735623af9214148afJeff Brown for (int i = 0; i < providerCount; i++) { 144111417b1cfde8f1749905f2d735623af9214148afJeff Brown ProviderInfo provider = mProviders.get(i); 144211417b1cfde8f1749905f2d735623af9214148afJeff Brown if (provider.isActiveScanRequired() && selector.matchesControlFilters( 144311417b1cfde8f1749905f2d735623af9214148afJeff Brown provider.getDiscoverableControlFilters())) { 144411417b1cfde8f1749905f2d735623af9214148afJeff Brown return true; 144511417b1cfde8f1749905f2d735623af9214148afJeff Brown } 144611417b1cfde8f1749905f2d735623af9214148afJeff Brown } 144711417b1cfde8f1749905f2d735623af9214148afJeff Brown } 144811417b1cfde8f1749905f2d735623af9214148afJeff Brown 144911417b1cfde8f1749905f2d735623af9214148afJeff Brown // It doesn't look like we can find a matching route right now. 145011417b1cfde8f1749905f2d735623af9214148afJeff Brown return false; 145111417b1cfde8f1749905f2d735623af9214148afJeff Brown } 145211417b1cfde8f1749905f2d735623af9214148afJeff Brown 145311417b1cfde8f1749905f2d735623af9214148afJeff Brown public void updateDiscoveryRequest() { 145411417b1cfde8f1749905f2d735623af9214148afJeff Brown // Combine all of the callback selectors and active scan flags. 145511417b1cfde8f1749905f2d735623af9214148afJeff Brown boolean activeScan = false; 145611417b1cfde8f1749905f2d735623af9214148afJeff Brown MediaRouteSelector.Builder builder = new MediaRouteSelector.Builder(); 145728520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown for (MediaRouter router : mRouters.values()) { 145811417b1cfde8f1749905f2d735623af9214148afJeff Brown final int count = router.mCallbackRecords.size(); 145911417b1cfde8f1749905f2d735623af9214148afJeff Brown for (int i = 0; i < count; i++) { 146011417b1cfde8f1749905f2d735623af9214148afJeff Brown CallbackRecord callback = router.mCallbackRecords.get(i); 146111417b1cfde8f1749905f2d735623af9214148afJeff Brown builder.addSelector(callback.mSelector); 146211417b1cfde8f1749905f2d735623af9214148afJeff Brown if ((callback.mFlags & CALLBACK_FLAG_ACTIVE_SCAN) != 0) { 146311417b1cfde8f1749905f2d735623af9214148afJeff Brown activeScan = true; 146411417b1cfde8f1749905f2d735623af9214148afJeff Brown } 146511417b1cfde8f1749905f2d735623af9214148afJeff Brown } 146611417b1cfde8f1749905f2d735623af9214148afJeff Brown } 146711417b1cfde8f1749905f2d735623af9214148afJeff Brown MediaRouteSelector selector = builder.build(); 146811417b1cfde8f1749905f2d735623af9214148afJeff Brown 146911417b1cfde8f1749905f2d735623af9214148afJeff Brown // Create a new discovery request. 147011417b1cfde8f1749905f2d735623af9214148afJeff Brown if (mDiscoveryRequest != null 147111417b1cfde8f1749905f2d735623af9214148afJeff Brown && mDiscoveryRequest.getSelector().equals(selector) 147211417b1cfde8f1749905f2d735623af9214148afJeff Brown && mDiscoveryRequest.isActiveScan() == activeScan) { 147311417b1cfde8f1749905f2d735623af9214148afJeff Brown return; // no change 147411417b1cfde8f1749905f2d735623af9214148afJeff Brown } 147511417b1cfde8f1749905f2d735623af9214148afJeff Brown if (selector.isEmpty() && !activeScan) { 147611417b1cfde8f1749905f2d735623af9214148afJeff Brown // Discovery is not needed. 147711417b1cfde8f1749905f2d735623af9214148afJeff Brown if (mDiscoveryRequest == null) { 147811417b1cfde8f1749905f2d735623af9214148afJeff Brown return; // no change 147911417b1cfde8f1749905f2d735623af9214148afJeff Brown } 148011417b1cfde8f1749905f2d735623af9214148afJeff Brown mDiscoveryRequest = null; 148111417b1cfde8f1749905f2d735623af9214148afJeff Brown } else { 148211417b1cfde8f1749905f2d735623af9214148afJeff Brown // Discovery is needed. 148311417b1cfde8f1749905f2d735623af9214148afJeff Brown mDiscoveryRequest = new MediaRouteDiscoveryRequest(selector, activeScan); 148411417b1cfde8f1749905f2d735623af9214148afJeff Brown } 148511417b1cfde8f1749905f2d735623af9214148afJeff Brown if (DEBUG) { 148611417b1cfde8f1749905f2d735623af9214148afJeff Brown Log.d(TAG, "Updated discovery request: " + mDiscoveryRequest); 148711417b1cfde8f1749905f2d735623af9214148afJeff Brown } 148811417b1cfde8f1749905f2d735623af9214148afJeff Brown 148911417b1cfde8f1749905f2d735623af9214148afJeff Brown // Notify providers. 149011417b1cfde8f1749905f2d735623af9214148afJeff Brown final int providerCount = mProviders.size(); 149111417b1cfde8f1749905f2d735623af9214148afJeff Brown for (int i = 0; i < providerCount; i++) { 149211417b1cfde8f1749905f2d735623af9214148afJeff Brown mProviders.get(i).mProviderInstance.setDiscoveryRequest(mDiscoveryRequest); 149328520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown } 149428520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown } 149528520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown 1496fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public void addProvider(MediaRouteProvider providerInstance) { 1497fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown int index = findProviderInfo(providerInstance); 1498c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (index < 0) { 1499c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown // 1. Add the provider to the list. 1500fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown ProviderInfo provider = new ProviderInfo(providerInstance); 1501fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mProviders.add(provider); 150211417b1cfde8f1749905f2d735623af9214148afJeff Brown if (DEBUG) { 150311417b1cfde8f1749905f2d735623af9214148afJeff Brown Log.d(TAG, "Provider added: " + provider); 150411417b1cfde8f1749905f2d735623af9214148afJeff Brown } 1505fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mCallbackHandler.post(CallbackHandler.MSG_PROVIDER_ADDED, provider); 1506c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown // 2. Create the provider's contents. 1507fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown updateProviderContents(provider, providerInstance.getDescriptor()); 1508c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown // 3. Register the provider callback. 150911417b1cfde8f1749905f2d735623af9214148afJeff Brown providerInstance.setCallback(mProviderCallback); 151011417b1cfde8f1749905f2d735623af9214148afJeff Brown // 4. Set the discovery request. 151111417b1cfde8f1749905f2d735623af9214148afJeff Brown providerInstance.setDiscoveryRequest(mDiscoveryRequest); 1512c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1513c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1514c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1515fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public void removeProvider(MediaRouteProvider providerInstance) { 1516fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown int index = findProviderInfo(providerInstance); 1517c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (index >= 0) { 151811417b1cfde8f1749905f2d735623af9214148afJeff Brown // 1. Unregister the provider callback. 151911417b1cfde8f1749905f2d735623af9214148afJeff Brown providerInstance.setCallback(null); 152011417b1cfde8f1749905f2d735623af9214148afJeff Brown // 2. Clear the discovery request. 152111417b1cfde8f1749905f2d735623af9214148afJeff Brown providerInstance.setDiscoveryRequest(null); 152228520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown // 3. Delete the provider's contents. 1523fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown ProviderInfo provider = mProviders.get(index); 1524fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown updateProviderContents(provider, null); 152528520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown // 4. Remove the provider from the list. 152611417b1cfde8f1749905f2d735623af9214148afJeff Brown if (DEBUG) { 152711417b1cfde8f1749905f2d735623af9214148afJeff Brown Log.d(TAG, "Provider removed: " + provider); 152811417b1cfde8f1749905f2d735623af9214148afJeff Brown } 1529fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mCallbackHandler.post(CallbackHandler.MSG_PROVIDER_REMOVED, provider); 1530fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mProviders.remove(index); 1531c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1532c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1533c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1534fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private void updateProviderDescriptor(MediaRouteProvider providerInstance, 153511417b1cfde8f1749905f2d735623af9214148afJeff Brown MediaRouteProviderDescriptor descriptor) { 1536fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown int index = findProviderInfo(providerInstance); 1537c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (index >= 0) { 1538fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown // Update the provider's contents. 1539fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown ProviderInfo provider = mProviders.get(index); 1540fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown updateProviderContents(provider, descriptor); 1541c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1542c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1543c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1544fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private int findProviderInfo(MediaRouteProvider providerInstance) { 1545fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown final int count = mProviders.size(); 1546c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown for (int i = 0; i < count; i++) { 1547fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (mProviders.get(i).mProviderInstance == providerInstance) { 1548c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return i; 1549c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1550c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1551c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return -1; 1552c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1553c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1554fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private void updateProviderContents(ProviderInfo provider, 155511417b1cfde8f1749905f2d735623af9214148afJeff Brown MediaRouteProviderDescriptor providerDescriptor) { 1556fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (provider.updateDescriptor(providerDescriptor)) { 1557c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown // Update all existing routes and reorder them to match 1558c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown // the order of their descriptors. 1559c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown int targetIndex = 0; 1560c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (providerDescriptor != null) { 1561fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (providerDescriptor.isValid()) { 156211417b1cfde8f1749905f2d735623af9214148afJeff Brown final List<MediaRouteDescriptor> routeDescriptors = 156311417b1cfde8f1749905f2d735623af9214148afJeff Brown providerDescriptor.getRoutes(); 156411417b1cfde8f1749905f2d735623af9214148afJeff Brown final int routeCount = routeDescriptors.size(); 156511417b1cfde8f1749905f2d735623af9214148afJeff Brown for (int i = 0; i < routeCount; i++) { 156611417b1cfde8f1749905f2d735623af9214148afJeff Brown final MediaRouteDescriptor routeDescriptor = routeDescriptors.get(i); 1567c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown final String id = routeDescriptor.getId(); 1568fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown final int sourceIndex = provider.findRouteByDescriptorId(id); 1569c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (sourceIndex < 0) { 1570c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown // 1. Add the route to the list. 1571fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown RouteInfo route = new RouteInfo(provider, id); 1572fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown provider.mRoutes.add(targetIndex++, route); 1573c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown mRoutes.add(route); 1574c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown // 2. Create the route's contents. 1575c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown route.updateDescriptor(routeDescriptor); 1576fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown // 3. Notify clients about addition. 157711417b1cfde8f1749905f2d735623af9214148afJeff Brown if (DEBUG) { 157811417b1cfde8f1749905f2d735623af9214148afJeff Brown Log.d(TAG, "Route added: " + route); 157911417b1cfde8f1749905f2d735623af9214148afJeff Brown } 1580c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown mCallbackHandler.post(CallbackHandler.MSG_ROUTE_ADDED, route); 1581fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } else if (sourceIndex < targetIndex) { 1582fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown Log.w(TAG, "Ignoring route descriptor with duplicate id: " 1583fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown + routeDescriptor); 1584c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } else { 1585c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown // 1. Reorder the route within the list. 1586fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown RouteInfo route = provider.mRoutes.get(sourceIndex); 1587fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown Collections.swap(provider.mRoutes, 1588c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown sourceIndex, targetIndex++); 1589c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown // 2. Update the route's contents. 1590c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown int changes = route.updateDescriptor(routeDescriptor); 1591fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown // 3. Unselect route if needed before notifying about changes. 1592fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown unselectRouteIfNeeded(route); 1593fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown // 4. Notify clients about changes. 1594c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if ((changes & RouteInfo.CHANGE_GENERAL) != 0) { 159511417b1cfde8f1749905f2d735623af9214148afJeff Brown if (DEBUG) { 159611417b1cfde8f1749905f2d735623af9214148afJeff Brown Log.d(TAG, "Route changed: " + route); 159711417b1cfde8f1749905f2d735623af9214148afJeff Brown } 1598c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown mCallbackHandler.post( 1599c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown CallbackHandler.MSG_ROUTE_CHANGED, route); 1600c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1601c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if ((changes & RouteInfo.CHANGE_VOLUME) != 0) { 160211417b1cfde8f1749905f2d735623af9214148afJeff Brown if (DEBUG) { 160311417b1cfde8f1749905f2d735623af9214148afJeff Brown Log.d(TAG, "Route volume changed: " + route); 160411417b1cfde8f1749905f2d735623af9214148afJeff Brown } 1605c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown mCallbackHandler.post( 1606c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown CallbackHandler.MSG_ROUTE_VOLUME_CHANGED, route); 1607c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1608c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if ((changes & RouteInfo.CHANGE_PRESENTATION_DISPLAY) != 0) { 160911417b1cfde8f1749905f2d735623af9214148afJeff Brown if (DEBUG) { 161011417b1cfde8f1749905f2d735623af9214148afJeff Brown Log.d(TAG, "Route presentation display changed: " 161111417b1cfde8f1749905f2d735623af9214148afJeff Brown + route); 161211417b1cfde8f1749905f2d735623af9214148afJeff Brown } 1613fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mCallbackHandler.post(CallbackHandler. 1614fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown MSG_ROUTE_PRESENTATION_DISPLAY_CHANGED, route); 1615c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1616c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1617c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1618fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } else { 1619fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown Log.w(TAG, "Ignoring invalid provider descriptor: " + providerDescriptor); 1620c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1621c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1622c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1623c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown // Dispose all remaining routes that do not have matching descriptors. 1624fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown for (int i = provider.mRoutes.size() - 1; i >= targetIndex; i--) { 1625fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown // 1. Delete the route's contents. 1626fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown RouteInfo route = provider.mRoutes.get(i); 1627c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown route.updateDescriptor(null); 1628fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown // 2. Remove the route from the list. 162911417b1cfde8f1749905f2d735623af9214148afJeff Brown mRoutes.remove(route); 1630fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown provider.mRoutes.remove(i); 1631fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown // 3. Unselect route if needed before notifying about removal. 1632fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown unselectRouteIfNeeded(route); 1633fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown // 4. Notify clients about removal. 163411417b1cfde8f1749905f2d735623af9214148afJeff Brown if (DEBUG) { 163511417b1cfde8f1749905f2d735623af9214148afJeff Brown Log.d(TAG, "Route removed: " + route); 163611417b1cfde8f1749905f2d735623af9214148afJeff Brown } 1637fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mCallbackHandler.post(CallbackHandler.MSG_ROUTE_REMOVED, route); 1638c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1639fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 164011417b1cfde8f1749905f2d735623af9214148afJeff Brown // Notify provider changed. 164111417b1cfde8f1749905f2d735623af9214148afJeff Brown if (DEBUG) { 164211417b1cfde8f1749905f2d735623af9214148afJeff Brown Log.d(TAG, "Provider changed: " + provider); 164311417b1cfde8f1749905f2d735623af9214148afJeff Brown } 164411417b1cfde8f1749905f2d735623af9214148afJeff Brown mCallbackHandler.post(CallbackHandler.MSG_PROVIDER_CHANGED, provider); 164511417b1cfde8f1749905f2d735623af9214148afJeff Brown 1646fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown // Choose a new selected route if needed. 1647fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown selectRouteIfNeeded(); 1648c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1649c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1650c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1651fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private void unselectRouteIfNeeded(RouteInfo route) { 1652fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (mDefaultRoute == route && !isRouteSelectable(route)) { 1653c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown Log.i(TAG, "Choosing a new default route because the current one " 1654fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown + "is no longer selectable: " + route); 1655c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown mDefaultRoute = null; 1656c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1657fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (mSelectedRoute == route && !isRouteSelectable(route)) { 1658fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown Log.i(TAG, "Choosing a new selected route because the current one " 1659fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown + "is no longer selectable: " + route); 1660fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown setSelectedRouteInternal(null); 1661fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 1662fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 1663fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 1664fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private void selectRouteIfNeeded() { 1665c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (mDefaultRoute == null && !mRoutes.isEmpty()) { 1666c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown for (RouteInfo route : mRoutes) { 1667c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (isSystemDefaultRoute(route) && isRouteSelectable(route)) { 1668c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown mDefaultRoute = route; 1669c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown break; 1670c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1671c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1672c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1673c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (mSelectedRoute == null) { 1674c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown setSelectedRouteInternal(mDefaultRoute); 1675c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1676c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1677c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1678c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown private boolean isRouteSelectable(RouteInfo route) { 1679c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown // This tests whether the route is still valid and enabled. 1680c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown // The route descriptor field is set to null when the route is removed. 1681c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return route.mDescriptor != null && route.mEnabled; 1682c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1683c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1684c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown private boolean isSystemDefaultRoute(RouteInfo route) { 1685fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return route.getProviderInstance() == mSystemProvider 1686c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown && route.mDescriptorId.equals( 1687c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown SystemMediaRouteProvider.DEFAULT_ROUTE_ID); 1688c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1689c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1690c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown private void setSelectedRouteInternal(RouteInfo route) { 1691c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (mSelectedRoute != route) { 1692c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (mSelectedRoute != null) { 169311417b1cfde8f1749905f2d735623af9214148afJeff Brown if (DEBUG) { 169411417b1cfde8f1749905f2d735623af9214148afJeff Brown Log.d(TAG, "Route unselected: " + mSelectedRoute); 169511417b1cfde8f1749905f2d735623af9214148afJeff Brown } 1696c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown mCallbackHandler.post(CallbackHandler.MSG_ROUTE_UNSELECTED, mSelectedRoute); 1697c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (mSelectedRouteController != null) { 1698129abf73ce9be1bc172b945263c7975ad1a3006fJeff Brown mSelectedRouteController.onUnselect(); 1699129abf73ce9be1bc172b945263c7975ad1a3006fJeff Brown mSelectedRouteController.onRelease(); 1700c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown mSelectedRouteController = null; 1701c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1702c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1703c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1704c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown mSelectedRoute = route; 1705c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1706c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (mSelectedRoute != null) { 1707fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mSelectedRouteController = route.getProviderInstance().onCreateRouteController( 1708c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown route.mDescriptorId); 1709c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (mSelectedRouteController != null) { 1710129abf73ce9be1bc172b945263c7975ad1a3006fJeff Brown mSelectedRouteController.onSelect(); 1711c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 171211417b1cfde8f1749905f2d735623af9214148afJeff Brown if (DEBUG) { 171311417b1cfde8f1749905f2d735623af9214148afJeff Brown Log.d(TAG, "Route selected: " + mSelectedRoute); 171411417b1cfde8f1749905f2d735623af9214148afJeff Brown } 1715c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown mCallbackHandler.post(CallbackHandler.MSG_ROUTE_SELECTED, mSelectedRoute); 1716c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1717c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1718c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1719c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1720c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown @Override 1721c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public RouteInfo getSystemRouteByDescriptorId(String id) { 1722fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown int providerIndex = findProviderInfo(mSystemProvider); 1723c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (providerIndex >= 0) { 1724fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown ProviderInfo provider = mProviders.get(providerIndex); 1725fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown int routeIndex = provider.findRouteByDescriptorId(id); 1726c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (routeIndex >= 0) { 1727fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return provider.mRoutes.get(routeIndex); 1728c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1729c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1730c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return null; 1731c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1732c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1733c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown private final class ProviderCallback extends MediaRouteProvider.Callback { 1734c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown @Override 1735c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public void onDescriptorChanged(MediaRouteProvider provider, 173611417b1cfde8f1749905f2d735623af9214148afJeff Brown MediaRouteProviderDescriptor descriptor) { 1737c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown updateProviderDescriptor(provider, descriptor); 1738c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1739c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1740c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1741c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown private final class CallbackHandler extends Handler { 1742c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown private final ArrayList<MediaRouter> mTempMediaRouters = 1743c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown new ArrayList<MediaRouter>(); 1744c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 174511417b1cfde8f1749905f2d735623af9214148afJeff Brown private static final int MSG_TYPE_MASK = 0xff00; 174611417b1cfde8f1749905f2d735623af9214148afJeff Brown private static final int MSG_TYPE_ROUTE = 0x0100; 174711417b1cfde8f1749905f2d735623af9214148afJeff Brown private static final int MSG_TYPE_PROVIDER = 0x0200; 174811417b1cfde8f1749905f2d735623af9214148afJeff Brown 174911417b1cfde8f1749905f2d735623af9214148afJeff Brown public static final int MSG_ROUTE_ADDED = MSG_TYPE_ROUTE | 1; 175011417b1cfde8f1749905f2d735623af9214148afJeff Brown public static final int MSG_ROUTE_REMOVED = MSG_TYPE_ROUTE | 2; 175111417b1cfde8f1749905f2d735623af9214148afJeff Brown public static final int MSG_ROUTE_CHANGED = MSG_TYPE_ROUTE | 3; 175211417b1cfde8f1749905f2d735623af9214148afJeff Brown public static final int MSG_ROUTE_VOLUME_CHANGED = MSG_TYPE_ROUTE | 4; 175311417b1cfde8f1749905f2d735623af9214148afJeff Brown public static final int MSG_ROUTE_PRESENTATION_DISPLAY_CHANGED = MSG_TYPE_ROUTE | 5; 175411417b1cfde8f1749905f2d735623af9214148afJeff Brown public static final int MSG_ROUTE_SELECTED = MSG_TYPE_ROUTE | 6; 175511417b1cfde8f1749905f2d735623af9214148afJeff Brown public static final int MSG_ROUTE_UNSELECTED = MSG_TYPE_ROUTE | 7; 175611417b1cfde8f1749905f2d735623af9214148afJeff Brown 175711417b1cfde8f1749905f2d735623af9214148afJeff Brown public static final int MSG_PROVIDER_ADDED = MSG_TYPE_PROVIDER | 1; 175811417b1cfde8f1749905f2d735623af9214148afJeff Brown public static final int MSG_PROVIDER_REMOVED = MSG_TYPE_PROVIDER | 2; 175911417b1cfde8f1749905f2d735623af9214148afJeff Brown public static final int MSG_PROVIDER_CHANGED = MSG_TYPE_PROVIDER | 3; 1760c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1761fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public void post(int msg, Object obj) { 1762fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown obtainMessage(msg, obj).sendToTarget(); 1763c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1764c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1765c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown @Override 1766c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public void handleMessage(Message msg) { 1767c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown final int what = msg.what; 1768fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown final Object obj = msg.obj; 1769c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1770c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown // Synchronize state with the system media router. 1771fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown syncWithSystemProvider(what, obj); 1772c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1773c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown // Invoke all registered callbacks. 1774c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown mTempMediaRouters.addAll(mRouters.values()); 1775c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown try { 1776c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown final int routerCount = mTempMediaRouters.size(); 1777c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown for (int i = 0; i < routerCount; i++) { 1778c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown final MediaRouter router = mTempMediaRouters.get(i); 177911417b1cfde8f1749905f2d735623af9214148afJeff Brown if (!router.mCallbackRecords.isEmpty()) { 178011417b1cfde8f1749905f2d735623af9214148afJeff Brown for (CallbackRecord record : router.mCallbackRecords) { 178111417b1cfde8f1749905f2d735623af9214148afJeff Brown invokeCallback(router, record, what, obj); 1782c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1783c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1784c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1785c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } finally { 1786c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown mTempMediaRouters.clear(); 1787c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1788c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1789c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1790fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private void syncWithSystemProvider(int what, Object obj) { 1791c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown switch (what) { 1792c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown case MSG_ROUTE_ADDED: 1793fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mSystemProvider.onSyncRouteAdded((RouteInfo)obj); 1794c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown break; 1795c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown case MSG_ROUTE_REMOVED: 1796fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mSystemProvider.onSyncRouteRemoved((RouteInfo)obj); 1797c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown break; 1798c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown case MSG_ROUTE_CHANGED: 1799fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mSystemProvider.onSyncRouteChanged((RouteInfo)obj); 1800c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown break; 1801c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown case MSG_ROUTE_SELECTED: 1802fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mSystemProvider.onSyncRouteSelected((RouteInfo)obj); 1803c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown break; 1804c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1805c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1806c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 180711417b1cfde8f1749905f2d735623af9214148afJeff Brown private void invokeCallback(MediaRouter router, CallbackRecord record, 1808fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown int what, Object obj) { 180911417b1cfde8f1749905f2d735623af9214148afJeff Brown final MediaRouter.Callback callback = record.mCallback; 181011417b1cfde8f1749905f2d735623af9214148afJeff Brown switch (what & MSG_TYPE_MASK) { 181111417b1cfde8f1749905f2d735623af9214148afJeff Brown case MSG_TYPE_ROUTE: { 181211417b1cfde8f1749905f2d735623af9214148afJeff Brown final RouteInfo route = (RouteInfo)obj; 181311417b1cfde8f1749905f2d735623af9214148afJeff Brown if (!record.filterRouteEvent(route)) { 181411417b1cfde8f1749905f2d735623af9214148afJeff Brown break; 181511417b1cfde8f1749905f2d735623af9214148afJeff Brown } 181611417b1cfde8f1749905f2d735623af9214148afJeff Brown switch (what) { 181711417b1cfde8f1749905f2d735623af9214148afJeff Brown case MSG_ROUTE_ADDED: 181811417b1cfde8f1749905f2d735623af9214148afJeff Brown callback.onRouteAdded(router, route); 181911417b1cfde8f1749905f2d735623af9214148afJeff Brown break; 182011417b1cfde8f1749905f2d735623af9214148afJeff Brown case MSG_ROUTE_REMOVED: 182111417b1cfde8f1749905f2d735623af9214148afJeff Brown callback.onRouteRemoved(router, route); 182211417b1cfde8f1749905f2d735623af9214148afJeff Brown break; 182311417b1cfde8f1749905f2d735623af9214148afJeff Brown case MSG_ROUTE_CHANGED: 182411417b1cfde8f1749905f2d735623af9214148afJeff Brown callback.onRouteChanged(router, route); 182511417b1cfde8f1749905f2d735623af9214148afJeff Brown break; 182611417b1cfde8f1749905f2d735623af9214148afJeff Brown case MSG_ROUTE_VOLUME_CHANGED: 182711417b1cfde8f1749905f2d735623af9214148afJeff Brown callback.onRouteVolumeChanged(router, route); 182811417b1cfde8f1749905f2d735623af9214148afJeff Brown break; 182911417b1cfde8f1749905f2d735623af9214148afJeff Brown case MSG_ROUTE_PRESENTATION_DISPLAY_CHANGED: 183011417b1cfde8f1749905f2d735623af9214148afJeff Brown callback.onRoutePresentationDisplayChanged(router, route); 183111417b1cfde8f1749905f2d735623af9214148afJeff Brown break; 183211417b1cfde8f1749905f2d735623af9214148afJeff Brown case MSG_ROUTE_SELECTED: 183311417b1cfde8f1749905f2d735623af9214148afJeff Brown callback.onRouteSelected(router, route); 183411417b1cfde8f1749905f2d735623af9214148afJeff Brown break; 183511417b1cfde8f1749905f2d735623af9214148afJeff Brown case MSG_ROUTE_UNSELECTED: 183611417b1cfde8f1749905f2d735623af9214148afJeff Brown callback.onRouteUnselected(router, route); 183711417b1cfde8f1749905f2d735623af9214148afJeff Brown break; 183811417b1cfde8f1749905f2d735623af9214148afJeff Brown } 1839c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown break; 184011417b1cfde8f1749905f2d735623af9214148afJeff Brown } 184111417b1cfde8f1749905f2d735623af9214148afJeff Brown case MSG_TYPE_PROVIDER: { 184211417b1cfde8f1749905f2d735623af9214148afJeff Brown final ProviderInfo provider = (ProviderInfo)obj; 184311417b1cfde8f1749905f2d735623af9214148afJeff Brown switch (what) { 184411417b1cfde8f1749905f2d735623af9214148afJeff Brown case MSG_PROVIDER_ADDED: 184511417b1cfde8f1749905f2d735623af9214148afJeff Brown callback.onProviderAdded(router, provider); 184611417b1cfde8f1749905f2d735623af9214148afJeff Brown break; 184711417b1cfde8f1749905f2d735623af9214148afJeff Brown case MSG_PROVIDER_REMOVED: 184811417b1cfde8f1749905f2d735623af9214148afJeff Brown callback.onProviderRemoved(router, provider); 184911417b1cfde8f1749905f2d735623af9214148afJeff Brown break; 185011417b1cfde8f1749905f2d735623af9214148afJeff Brown case MSG_PROVIDER_CHANGED: 185111417b1cfde8f1749905f2d735623af9214148afJeff Brown callback.onProviderChanged(router, provider); 185211417b1cfde8f1749905f2d735623af9214148afJeff Brown break; 185311417b1cfde8f1749905f2d735623af9214148afJeff Brown } 185411417b1cfde8f1749905f2d735623af9214148afJeff Brown } 1855c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1856c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1857c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1858c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1859c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown} 1860