MediaRouter.java revision 9942d40d0d952b03b583fe66f434676793697aa2
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 1169942d40d0d952b03b583fe66f434676793697aa2Jeff Brown * determine whether route providers that require active scans might discover 1179942d40d0d952b03b583fe66f434676793697aa2Jeff Brown * 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. 1209942d40d0d952b03b583fe66f434676793697aa2Jeff Brown * When the dialog is opened, route providers are provided an opportunity 1219942d40d0d952b03b583fe66f434676793697aa2Jeff Brown * to perform active scans to discover additional routes. 12211417b1cfde8f1749905f2d735623af9214148afJeff Brown * </p> 1239942d40d0d952b03b583fe66f434676793697aa2Jeff Brown * 1249942d40d0d952b03b583fe66f434676793697aa2Jeff Brown * @see #CALLBACK_FLAG_ACTIVE_SCAN 12511417b1cfde8f1749905f2d735623af9214148afJeff Brown */ 12611417b1cfde8f1749905f2d735623af9214148afJeff Brown public static final int AVAILABILITY_FLAG_CONSIDER_ACTIVE_SCAN = 1 << 1; 127c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 128c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown MediaRouter(Context context) { 129c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown mContext = context; 130c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 131c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 132c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 133c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Gets an instance of the media router service from the context. 134c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 135c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public static MediaRouter getInstance(Context context) { 136c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (context == null) { 137c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown throw new IllegalArgumentException("context must not be null"); 138c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 139c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown checkCallingThread(); 140c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 141c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (sGlobal == null) { 142c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown sGlobal = new GlobalMediaRouter(context.getApplicationContext()); 143fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown sGlobal.start(); 144c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 145c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return sGlobal.getRouter(context); 146c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 147c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 148c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 149fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * Gets information about the {@link MediaRouter.RouteInfo routes} currently known to 150fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * this media router. 151c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 152c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public List<RouteInfo> getRoutes() { 153c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown checkCallingThread(); 154c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return sGlobal.getRoutes(); 155c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 156c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 157c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 158fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * Gets information about the {@link MediaRouter.ProviderInfo route providers} 159fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * currently known to this media router. 160fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown */ 161fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public List<ProviderInfo> getProviders() { 162fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown checkCallingThread(); 163fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return sGlobal.getProviders(); 164fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 165fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 166fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown /** 167c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Gets the default route for playing media content on the system. 168c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * <p> 169c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * The system always provides a default route. 170c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * </p> 171c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 172c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @return The default route, which is guaranteed to never be null. 173c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 174c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public RouteInfo getDefaultRoute() { 175c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown checkCallingThread(); 176c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return sGlobal.getDefaultRoute(); 177c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 178c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 179c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 180c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Gets the currently selected route. 181c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * <p> 182c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * The application should examine the route's 183fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * {@link RouteInfo#getControlFilters media control intent filters} to assess the 184c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * capabilities of the route before attempting to use it. 185c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * </p> 186c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 187c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * <h3>Example</h3> 188c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * <pre> 189c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * public boolean playMovie() { 190c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * MediaRouter mediaRouter = MediaRouter.getInstance(context); 191c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * MediaRouter.RouteInfo route = mediaRouter.getSelectedRoute(); 192c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 193c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * // First try using the remote playback interface, if supported. 194c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * if (route.supportsControlCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK)) { 195c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * // The route supports remote playback. 196c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * // Try to send it the Uri of the movie to play. 197c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Intent intent = new Intent(MediaControlIntent.ACTION_PLAY); 198c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * intent.addCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK); 199c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * intent.setDataAndType("http://example.com/videos/movie.mp4", "video/mp4"); 200fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * if (route.supportsControlRequest(intent)) { 201fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * route.sendControlRequest(intent, null); 202fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * return true; // sent the request to play the movie 203c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * } 204c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * } 205c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 206c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * // If remote playback was not possible, then play locally. 207c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * if (route.supportsControlCategory(MediaControlIntent.CATEGORY_LIVE_VIDEO)) { 208c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * // The route supports live video streaming. 209c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * // Prepare to play content locally in a window or in a presentation. 210c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * return playMovieInWindow(); 211c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * } 212c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 213c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * // Neither interface is supported, so we can't play the movie to this route. 214c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * return false; 215c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * } 216c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * </pre> 217c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 218c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @return The selected route, which is guaranteed to never be null. 219c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 220fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * @see RouteInfo#getControlFilters 221c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @see RouteInfo#supportsControlCategory 222c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @see RouteInfo#supportsControlRequest 223c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 224c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public RouteInfo getSelectedRoute() { 225c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown checkCallingThread(); 226c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return sGlobal.getSelectedRoute(); 227c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 228c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 229c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 23028520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown * Returns the selected route if it matches the specified selector, otherwise 23128520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown * selects the default route and returns it. 23228520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown * 23328520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown * @param selector The selector to match. 23428520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown * @return The previously selected route if it matched the selector, otherwise the 23528520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown * newly selected default route which is guaranteed to never be null. 23628520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown * 23711417b1cfde8f1749905f2d735623af9214148afJeff Brown * @see MediaRouteSelector 23828520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown * @see RouteInfo#matchesSelector 23928520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown * @see RouteInfo#isDefault 24028520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown */ 24111417b1cfde8f1749905f2d735623af9214148afJeff Brown public RouteInfo updateSelectedRoute(MediaRouteSelector selector) { 24228520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown if (selector == null) { 24328520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown throw new IllegalArgumentException("selector must not be null"); 24428520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown } 24528520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown checkCallingThread(); 24628520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown 24711417b1cfde8f1749905f2d735623af9214148afJeff Brown if (DEBUG) { 24811417b1cfde8f1749905f2d735623af9214148afJeff Brown Log.d(TAG, "updateSelectedRoute: " + selector); 24911417b1cfde8f1749905f2d735623af9214148afJeff Brown } 25028520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown RouteInfo route = sGlobal.getSelectedRoute(); 25111417b1cfde8f1749905f2d735623af9214148afJeff Brown if (!route.isDefault() && !route.matchesSelector(selector)) { 25228520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown route = sGlobal.getDefaultRoute(); 25328520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown sGlobal.selectRoute(route); 25428520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown } 25528520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown return route; 25628520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown } 25728520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown 25828520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown /** 259c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Selects the specified route. 260c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 261c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @param route The route to select. 262c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 263c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public void selectRoute(RouteInfo route) { 264c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (route == null) { 265c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown throw new IllegalArgumentException("route must not be null"); 266c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 267c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown checkCallingThread(); 268c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 26911417b1cfde8f1749905f2d735623af9214148afJeff Brown if (DEBUG) { 27011417b1cfde8f1749905f2d735623af9214148afJeff Brown Log.d(TAG, "selectRoute: " + route); 27111417b1cfde8f1749905f2d735623af9214148afJeff Brown } 272c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown sGlobal.selectRoute(route); 273c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 274c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 275c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 27611417b1cfde8f1749905f2d735623af9214148afJeff Brown * Returns true if there is a route that matches the specified selector 27711417b1cfde8f1749905f2d735623af9214148afJeff Brown * or, depending on the specified availability flags, if it is possible to discover one. 27811417b1cfde8f1749905f2d735623af9214148afJeff Brown * <p> 27911417b1cfde8f1749905f2d735623af9214148afJeff Brown * This method first considers whether there are any available 28011417b1cfde8f1749905f2d735623af9214148afJeff Brown * routes that match the selector regardless of whether they are enabled or 28111417b1cfde8f1749905f2d735623af9214148afJeff Brown * disabled. If not and the {@link #AVAILABILITY_FLAG_CONSIDER_ACTIVE_SCAN} flag 28211417b1cfde8f1749905f2d735623af9214148afJeff Brown * was specifies, then it considers whether any of the route providers 28311417b1cfde8f1749905f2d735623af9214148afJeff Brown * could discover a matching route if an active scan were performed. 28411417b1cfde8f1749905f2d735623af9214148afJeff Brown * </p> 285c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 28611417b1cfde8f1749905f2d735623af9214148afJeff Brown * @param selector The selector to match. 28711417b1cfde8f1749905f2d735623af9214148afJeff Brown * @param flags Flags to control the determination of whether a route may be available. 28811417b1cfde8f1749905f2d735623af9214148afJeff Brown * May be zero or a combination of 28911417b1cfde8f1749905f2d735623af9214148afJeff Brown * {@link #AVAILABILITY_FLAG_IGNORE_DEFAULT_ROUTE} and 29011417b1cfde8f1749905f2d735623af9214148afJeff Brown * {@link #AVAILABILITY_FLAG_CONSIDER_ACTIVE_SCAN}. 29111417b1cfde8f1749905f2d735623af9214148afJeff Brown * @return True if a matching route may be available. 292c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 29311417b1cfde8f1749905f2d735623af9214148afJeff Brown public boolean isRouteAvailable(MediaRouteSelector selector, int flags) { 29411417b1cfde8f1749905f2d735623af9214148afJeff Brown if (selector == null) { 29511417b1cfde8f1749905f2d735623af9214148afJeff Brown throw new IllegalArgumentException("selector must not be null"); 296c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 297c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown checkCallingThread(); 298c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 29911417b1cfde8f1749905f2d735623af9214148afJeff Brown return sGlobal.isRouteAvailable(selector, flags); 300c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 301c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 302c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 30311417b1cfde8f1749905f2d735623af9214148afJeff Brown * Registers a callback to discover routes that match the selector and to receive 30411417b1cfde8f1749905f2d735623af9214148afJeff Brown * events when they change. 30511417b1cfde8f1749905f2d735623af9214148afJeff Brown * <p> 30611417b1cfde8f1749905f2d735623af9214148afJeff Brown * This is a convenience method that has the same effect as calling 30711417b1cfde8f1749905f2d735623af9214148afJeff Brown * {@link #addCallback(MediaRouteSelector, Callback, int)} without flags. 30811417b1cfde8f1749905f2d735623af9214148afJeff Brown * </p> 309c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 31011417b1cfde8f1749905f2d735623af9214148afJeff Brown * @param selector A route selector that indicates the kinds of routes that the 31111417b1cfde8f1749905f2d735623af9214148afJeff Brown * callback would like to discover. 31211417b1cfde8f1749905f2d735623af9214148afJeff Brown * @param callback The callback to add. 31311417b1cfde8f1749905f2d735623af9214148afJeff Brown * @see #removeCallback 314c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 31511417b1cfde8f1749905f2d735623af9214148afJeff Brown public void addCallback(MediaRouteSelector selector, Callback callback) { 31611417b1cfde8f1749905f2d735623af9214148afJeff Brown addCallback(selector, callback, 0); 317c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 318c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 319c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 32011417b1cfde8f1749905f2d735623af9214148afJeff Brown * Registers a callback to discover routes that match the selector and to receive 32111417b1cfde8f1749905f2d735623af9214148afJeff Brown * events when they change. 32228520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown * <p> 32311417b1cfde8f1749905f2d735623af9214148afJeff Brown * The selector describes the kinds of routes that the application wants to 32411417b1cfde8f1749905f2d735623af9214148afJeff Brown * discover. For example, if the application wants to use 32511417b1cfde8f1749905f2d735623af9214148afJeff Brown * live audio routes then it should include the 32611417b1cfde8f1749905f2d735623af9214148afJeff Brown * {@link MediaControlIntent#CATEGORY_LIVE_AUDIO live audio media control intent category} 32711417b1cfde8f1749905f2d735623af9214148afJeff Brown * in its selector when it adds a callback to the media router. 32811417b1cfde8f1749905f2d735623af9214148afJeff Brown * The selector may include any number of categories. 32928520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown * </p><p> 33011417b1cfde8f1749905f2d735623af9214148afJeff Brown * If the callback has already been registered, then the selector is added to 33111417b1cfde8f1749905f2d735623af9214148afJeff Brown * the set of selectors being monitored by the callback. 33211417b1cfde8f1749905f2d735623af9214148afJeff Brown * </p><p> 33311417b1cfde8f1749905f2d735623af9214148afJeff Brown * By default, the callback will only be invoked for events that affect routes 33411417b1cfde8f1749905f2d735623af9214148afJeff Brown * that match the specified selector. Event filtering may be disabled by specifying 33511417b1cfde8f1749905f2d735623af9214148afJeff Brown * the {@link #CALLBACK_FLAG_UNFILTERED_EVENTS} flag when the callback is registered. 33628520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown * </p> 33728520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown * 33828520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown * <h3>Example</h3> 33928520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown * <pre> 34011417b1cfde8f1749905f2d735623af9214148afJeff Brown * public class MyActivity extends Activity { 34111417b1cfde8f1749905f2d735623af9214148afJeff Brown * private MediaRouter mRouter; 34211417b1cfde8f1749905f2d735623af9214148afJeff Brown * private MediaRouter.Callback mCallback; 34311417b1cfde8f1749905f2d735623af9214148afJeff Brown * private MediaRouteSelector mSelector; 34428520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown * 34511417b1cfde8f1749905f2d735623af9214148afJeff Brown * protected void onCreate(Bundle savedInstanceState) { 34611417b1cfde8f1749905f2d735623af9214148afJeff Brown * super.onCreate(savedInstanceState); 34711417b1cfde8f1749905f2d735623af9214148afJeff Brown * 34811417b1cfde8f1749905f2d735623af9214148afJeff Brown * mRouter = Mediarouter.getInstance(this); 34911417b1cfde8f1749905f2d735623af9214148afJeff Brown * mCallback = new MyCallback(); 35011417b1cfde8f1749905f2d735623af9214148afJeff Brown * mSelector = new MediaRouteSelector.Builder() 35111417b1cfde8f1749905f2d735623af9214148afJeff Brown * .addControlCategory(MediaControlIntent.CATEGORY_LIVE_AUDIO) 35211417b1cfde8f1749905f2d735623af9214148afJeff Brown * .addControlCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK) 35311417b1cfde8f1749905f2d735623af9214148afJeff Brown * .build(); 35428520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown * } 35528520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown * 35611417b1cfde8f1749905f2d735623af9214148afJeff Brown * // Add the callback on resume to tell the media router what kinds of routes 35711417b1cfde8f1749905f2d735623af9214148afJeff Brown * // the application is interested in so that it can try to discover suitable ones. 35811417b1cfde8f1749905f2d735623af9214148afJeff Brown * public void onResume() { 35911417b1cfde8f1749905f2d735623af9214148afJeff Brown * super.onResume(); 36011417b1cfde8f1749905f2d735623af9214148afJeff Brown * 36111417b1cfde8f1749905f2d735623af9214148afJeff Brown * mediaRouter.addCallback(mSelector, mCallback); 36211417b1cfde8f1749905f2d735623af9214148afJeff Brown * 36311417b1cfde8f1749905f2d735623af9214148afJeff Brown * MediaRouter.RouteInfo route = mediaRouter.updateSelectedRoute(mSelector); 36411417b1cfde8f1749905f2d735623af9214148afJeff Brown * // do something with the route... 36511417b1cfde8f1749905f2d735623af9214148afJeff Brown * } 36611417b1cfde8f1749905f2d735623af9214148afJeff Brown * 36711417b1cfde8f1749905f2d735623af9214148afJeff Brown * // Remove the selector on pause to tell the media router that it no longer 36811417b1cfde8f1749905f2d735623af9214148afJeff Brown * // needs to invest effort trying to discover routes of these kinds for now. 36911417b1cfde8f1749905f2d735623af9214148afJeff Brown * public void onPause() { 37011417b1cfde8f1749905f2d735623af9214148afJeff Brown * super.onPause(); 37111417b1cfde8f1749905f2d735623af9214148afJeff Brown * 37211417b1cfde8f1749905f2d735623af9214148afJeff Brown * mediaRouter.removeCallback(mCallback); 37311417b1cfde8f1749905f2d735623af9214148afJeff Brown * } 37411417b1cfde8f1749905f2d735623af9214148afJeff Brown * 37511417b1cfde8f1749905f2d735623af9214148afJeff Brown * private final class MyCallback extends MediaRouter.Callback { 37611417b1cfde8f1749905f2d735623af9214148afJeff Brown * // Implement callback methods as needed. 37728520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown * } 37828520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown * } 37928520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown * </pre> 38028520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown * 38111417b1cfde8f1749905f2d735623af9214148afJeff Brown * @param selector A route selector that indicates the kinds of routes that the 38211417b1cfde8f1749905f2d735623af9214148afJeff Brown * callback would like to discover. 38311417b1cfde8f1749905f2d735623af9214148afJeff Brown * @param callback The callback to add. 38411417b1cfde8f1749905f2d735623af9214148afJeff Brown * @param flags Flags to control the behavior of the callback. 38511417b1cfde8f1749905f2d735623af9214148afJeff Brown * May be zero or a combination of {@link #CALLBACK_FLAG_ACTIVE_SCAN} and 38611417b1cfde8f1749905f2d735623af9214148afJeff Brown * {@link #CALLBACK_FLAG_UNFILTERED_EVENTS}. 38711417b1cfde8f1749905f2d735623af9214148afJeff Brown * @see #removeCallback 38828520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown */ 38911417b1cfde8f1749905f2d735623af9214148afJeff Brown public void addCallback(MediaRouteSelector selector, Callback callback, int flags) { 39028520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown if (selector == null) { 39128520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown throw new IllegalArgumentException("selector must not be null"); 39228520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown } 39311417b1cfde8f1749905f2d735623af9214148afJeff Brown if (callback == null) { 39411417b1cfde8f1749905f2d735623af9214148afJeff Brown throw new IllegalArgumentException("callback must not be null"); 39511417b1cfde8f1749905f2d735623af9214148afJeff Brown } 39628520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown checkCallingThread(); 39728520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown 39811417b1cfde8f1749905f2d735623af9214148afJeff Brown if (DEBUG) { 39911417b1cfde8f1749905f2d735623af9214148afJeff Brown Log.d(TAG, "addCallback: selector=" + selector 40011417b1cfde8f1749905f2d735623af9214148afJeff Brown + ", callback=" + callback + ", flags=" + Integer.toHexString(flags)); 40111417b1cfde8f1749905f2d735623af9214148afJeff Brown } 40211417b1cfde8f1749905f2d735623af9214148afJeff Brown 40311417b1cfde8f1749905f2d735623af9214148afJeff Brown CallbackRecord record; 40411417b1cfde8f1749905f2d735623af9214148afJeff Brown int index = findCallbackRecord(callback); 40511417b1cfde8f1749905f2d735623af9214148afJeff Brown if (index < 0) { 40611417b1cfde8f1749905f2d735623af9214148afJeff Brown record = new CallbackRecord(callback); 40711417b1cfde8f1749905f2d735623af9214148afJeff Brown mCallbackRecords.add(record); 40811417b1cfde8f1749905f2d735623af9214148afJeff Brown } else { 40911417b1cfde8f1749905f2d735623af9214148afJeff Brown record = mCallbackRecords.get(index); 41011417b1cfde8f1749905f2d735623af9214148afJeff Brown } 41111417b1cfde8f1749905f2d735623af9214148afJeff Brown boolean updateNeeded = false; 41211417b1cfde8f1749905f2d735623af9214148afJeff Brown if ((flags & ~record.mFlags) != 0) { 41311417b1cfde8f1749905f2d735623af9214148afJeff Brown record.mFlags |= flags; 41411417b1cfde8f1749905f2d735623af9214148afJeff Brown updateNeeded = true; 41511417b1cfde8f1749905f2d735623af9214148afJeff Brown } 41611417b1cfde8f1749905f2d735623af9214148afJeff Brown if (!record.mSelector.contains(selector)) { 41711417b1cfde8f1749905f2d735623af9214148afJeff Brown record.mSelector = new MediaRouteSelector.Builder(record.mSelector) 41811417b1cfde8f1749905f2d735623af9214148afJeff Brown .addSelector(selector) 41911417b1cfde8f1749905f2d735623af9214148afJeff Brown .build(); 42011417b1cfde8f1749905f2d735623af9214148afJeff Brown updateNeeded = true; 42111417b1cfde8f1749905f2d735623af9214148afJeff Brown } 42211417b1cfde8f1749905f2d735623af9214148afJeff Brown if (updateNeeded) { 42311417b1cfde8f1749905f2d735623af9214148afJeff Brown sGlobal.updateDiscoveryRequest(); 42428520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown } 42528520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown } 42628520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown 42728520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown /** 42811417b1cfde8f1749905f2d735623af9214148afJeff Brown * Removes the specified callback. It will no longer receive events about 42911417b1cfde8f1749905f2d735623af9214148afJeff Brown * changes to media routes. 43028520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown * 43111417b1cfde8f1749905f2d735623af9214148afJeff Brown * @param callback The callback to remove. 43211417b1cfde8f1749905f2d735623af9214148afJeff Brown * @see #addCallback 43328520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown */ 43411417b1cfde8f1749905f2d735623af9214148afJeff Brown public void removeCallback(Callback callback) { 43511417b1cfde8f1749905f2d735623af9214148afJeff Brown if (callback == null) { 43611417b1cfde8f1749905f2d735623af9214148afJeff Brown throw new IllegalArgumentException("callback must not be null"); 43728520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown } 43828520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown checkCallingThread(); 43928520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown 44011417b1cfde8f1749905f2d735623af9214148afJeff Brown if (DEBUG) { 44111417b1cfde8f1749905f2d735623af9214148afJeff Brown Log.d(TAG, "removeCallback: callback=" + callback); 44211417b1cfde8f1749905f2d735623af9214148afJeff Brown } 44311417b1cfde8f1749905f2d735623af9214148afJeff Brown 44411417b1cfde8f1749905f2d735623af9214148afJeff Brown int index = findCallbackRecord(callback); 44511417b1cfde8f1749905f2d735623af9214148afJeff Brown if (index >= 0) { 44611417b1cfde8f1749905f2d735623af9214148afJeff Brown mCallbackRecords.remove(index); 44711417b1cfde8f1749905f2d735623af9214148afJeff Brown sGlobal.updateDiscoveryRequest(); 44828520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown } 44928520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown } 45028520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown 45111417b1cfde8f1749905f2d735623af9214148afJeff Brown private int findCallbackRecord(Callback callback) { 45211417b1cfde8f1749905f2d735623af9214148afJeff Brown final int count = mCallbackRecords.size(); 45311417b1cfde8f1749905f2d735623af9214148afJeff Brown for (int i = 0; i < count; i++) { 45411417b1cfde8f1749905f2d735623af9214148afJeff Brown if (mCallbackRecords.get(i).mCallback == callback) { 45511417b1cfde8f1749905f2d735623af9214148afJeff Brown return i; 45611417b1cfde8f1749905f2d735623af9214148afJeff Brown } 45711417b1cfde8f1749905f2d735623af9214148afJeff Brown } 45811417b1cfde8f1749905f2d735623af9214148afJeff Brown return -1; 45911417b1cfde8f1749905f2d735623af9214148afJeff Brown } 46011417b1cfde8f1749905f2d735623af9214148afJeff Brown 46128520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown /** 4629942d40d0d952b03b583fe66f434676793697aa2Jeff Brown * Registers a media route provider within this application process. 4639942d40d0d952b03b583fe66f434676793697aa2Jeff Brown * <p> 4649942d40d0d952b03b583fe66f434676793697aa2Jeff Brown * The provider will be added to the list of providers that all {@link MediaRouter} 4659942d40d0d952b03b583fe66f434676793697aa2Jeff Brown * instances within this process can use to discover routes. 4669942d40d0d952b03b583fe66f434676793697aa2Jeff Brown * </p> 467c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 468fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * @param providerInstance The media route provider instance to add. 469c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 470c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @see MediaRouteProvider 47128520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown * @see #removeCallback 472c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 473fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public void addProvider(MediaRouteProvider providerInstance) { 474fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (providerInstance == null) { 475fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown throw new IllegalArgumentException("providerInstance must not be null"); 476c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 477c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown checkCallingThread(); 478c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 47911417b1cfde8f1749905f2d735623af9214148afJeff Brown if (DEBUG) { 48011417b1cfde8f1749905f2d735623af9214148afJeff Brown Log.d(TAG, "addProvider: " + providerInstance); 48111417b1cfde8f1749905f2d735623af9214148afJeff Brown } 482fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown sGlobal.addProvider(providerInstance); 483c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 484c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 485c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 4869942d40d0d952b03b583fe66f434676793697aa2Jeff Brown * Unregisters a media route provider within this application process. 4879942d40d0d952b03b583fe66f434676793697aa2Jeff Brown * <p> 4889942d40d0d952b03b583fe66f434676793697aa2Jeff Brown * The provider will be removed from the list of providers that all {@link MediaRouter} 4899942d40d0d952b03b583fe66f434676793697aa2Jeff Brown * instances within this process can use to discover routes. 4909942d40d0d952b03b583fe66f434676793697aa2Jeff Brown * </p> 491c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 492fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * @param providerInstance The media route provider instance to remove. 493c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 494c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @see MediaRouteProvider 49528520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown * @see #addCallback 496c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 497fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public void removeProvider(MediaRouteProvider providerInstance) { 498fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (providerInstance == null) { 499fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown throw new IllegalArgumentException("providerInstance must not be null"); 500c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 501c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown checkCallingThread(); 502c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 50311417b1cfde8f1749905f2d735623af9214148afJeff Brown if (DEBUG) { 50411417b1cfde8f1749905f2d735623af9214148afJeff Brown Log.d(TAG, "removeProvider: " + providerInstance); 50528520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown } 50611417b1cfde8f1749905f2d735623af9214148afJeff Brown sGlobal.removeProvider(providerInstance); 50728520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown } 50828520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown 50928520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown /** 510c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Ensures that calls into the media router are on the correct thread. 511c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * It pays to be a little paranoid when global state invariants are at risk. 512c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 513c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown static void checkCallingThread() { 514c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (Looper.myLooper() != Looper.getMainLooper()) { 515c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown throw new IllegalStateException("The media router service must only be " 516c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown + "accessed on the application's main thread."); 517c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 518c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 519c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 520c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown static <T> boolean equal(T a, T b) { 521c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return a == b || (a != null && b != null && a.equals(b)); 522c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 523c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 524c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 525c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Provides information about a media route. 526c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * <p> 527fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * Each media route has a list of {@link MediaControlIntent media control} 528fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * {@link #getControlFilters intent filters} that describe the capabilities of the 529c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * route and the manner in which it is used and controlled. 530c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * </p> 531c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 532c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public static final class RouteInfo { 533fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private final ProviderInfo mProvider; 534c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown private final String mDescriptorId; 535c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown private String mName; 536d63957d28aaabcec588b8cde12eac16414783aebJeff Brown private String mDescription; 537c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown private boolean mEnabled; 53811417b1cfde8f1749905f2d735623af9214148afJeff Brown private boolean mConnecting; 539fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private final ArrayList<IntentFilter> mControlFilters = new ArrayList<IntentFilter>(); 540c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown private int mPlaybackType; 541c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown private int mPlaybackStream; 542c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown private int mVolumeHandling; 543c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown private int mVolume; 544c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown private int mVolumeMax; 545c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown private Display mPresentationDisplay; 546c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown private int mPresentationDisplayId = -1; 547c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown private Bundle mExtras; 54811417b1cfde8f1749905f2d735623af9214148afJeff Brown private MediaRouteDescriptor mDescriptor; 549c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 550c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 551c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * The default playback type, "local", indicating the presentation of the media 552c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * is happening on the same device (e.g. a phone, a tablet) as where it is 553c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * controlled from. 554c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 555c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @see #getPlaybackType 556c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 557c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public static final int PLAYBACK_TYPE_LOCAL = 0; 558c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 559c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 560c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * A playback type indicating the presentation of the media is happening on 561c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * a different device (i.e. the remote device) than where it is controlled from. 562c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 563c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @see #getPlaybackType 564c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 565c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public static final int PLAYBACK_TYPE_REMOTE = 1; 566c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 567c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 568c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Playback information indicating the playback volume is fixed, i.e. it cannot be 569c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * controlled from this object. An example of fixed playback volume is a remote player, 570c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * playing over HDMI where the user prefers to control the volume on the HDMI sink, rather 571c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * than attenuate at the source. 572c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 573c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @see #getVolumeHandling 574c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 575c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public static final int PLAYBACK_VOLUME_FIXED = 0; 576c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 577c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 578c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Playback information indicating the playback volume is variable and can be controlled 579c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * from this object. 580c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 581c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @see #getVolumeHandling 582c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 583c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public static final int PLAYBACK_VOLUME_VARIABLE = 1; 584c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 585c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown static final int CHANGE_GENERAL = 1 << 0; 586c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown static final int CHANGE_VOLUME = 1 << 1; 587c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown static final int CHANGE_PRESENTATION_DISPLAY = 1 << 2; 588c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 589fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown RouteInfo(ProviderInfo provider, String descriptorId) { 590fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mProvider = provider; 591c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown mDescriptorId = descriptorId; 592c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 593c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 594fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown /** 595fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * Gets information about the provider of this media route. 596fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown */ 597fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public ProviderInfo getProvider() { 598fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return mProvider; 599c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 600c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 601c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 602d63957d28aaabcec588b8cde12eac16414783aebJeff Brown * Gets the user-visible name of the route. 603d63957d28aaabcec588b8cde12eac16414783aebJeff Brown * <p> 604d63957d28aaabcec588b8cde12eac16414783aebJeff Brown * The route name identifies the destination represented by the route. 605d63957d28aaabcec588b8cde12eac16414783aebJeff Brown * It may be a user-supplied name, an alias, or device serial number. 606d63957d28aaabcec588b8cde12eac16414783aebJeff Brown * </p> 607c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 608d63957d28aaabcec588b8cde12eac16414783aebJeff Brown * @return The user-visible name of a media route. This is the string presented 609c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * to users who may select this as the active route. 610c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 611c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public String getName() { 612c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return mName; 613c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 614c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 615c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 616d63957d28aaabcec588b8cde12eac16414783aebJeff Brown * Gets the user-visible description of the route. 617d63957d28aaabcec588b8cde12eac16414783aebJeff Brown * <p> 618d63957d28aaabcec588b8cde12eac16414783aebJeff Brown * The route description describes the kind of destination represented by the route. 619d63957d28aaabcec588b8cde12eac16414783aebJeff Brown * It may be a user-supplied string, a model number or brand of device. 620d63957d28aaabcec588b8cde12eac16414783aebJeff Brown * </p> 621c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 622d63957d28aaabcec588b8cde12eac16414783aebJeff Brown * @return The description of the route, or null if none. 623c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 624d63957d28aaabcec588b8cde12eac16414783aebJeff Brown public String getDescription() { 625d63957d28aaabcec588b8cde12eac16414783aebJeff Brown return mDescription; 626c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 627c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 628c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 629c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Returns true if this route is enabled and may be selected. 630c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 63111417b1cfde8f1749905f2d735623af9214148afJeff Brown * @return True if this route is enabled. 632c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 633c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public boolean isEnabled() { 634c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return mEnabled; 635c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 636c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 637c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 63811417b1cfde8f1749905f2d735623af9214148afJeff Brown * Returns true if the route is in the process of connecting and is not 63911417b1cfde8f1749905f2d735623af9214148afJeff Brown * yet ready for use. 64011417b1cfde8f1749905f2d735623af9214148afJeff Brown * 64111417b1cfde8f1749905f2d735623af9214148afJeff Brown * @return True if this route is in the process of connecting. 64211417b1cfde8f1749905f2d735623af9214148afJeff Brown */ 64311417b1cfde8f1749905f2d735623af9214148afJeff Brown public boolean isConnecting() { 64411417b1cfde8f1749905f2d735623af9214148afJeff Brown return mConnecting; 64511417b1cfde8f1749905f2d735623af9214148afJeff Brown } 64611417b1cfde8f1749905f2d735623af9214148afJeff Brown 64711417b1cfde8f1749905f2d735623af9214148afJeff Brown /** 648fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * Returns true if this route is currently selected. 649c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 65011417b1cfde8f1749905f2d735623af9214148afJeff Brown * @return True if this route is currently selected. 651fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * 652fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * @see MediaRouter#getSelectedRoute 653fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown */ 654fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public boolean isSelected() { 655fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown checkCallingThread(); 656fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return sGlobal.getSelectedRoute() == this; 657fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 658fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 659fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown /** 660fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * Returns true if this route is the default route. 661fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * 66211417b1cfde8f1749905f2d735623af9214148afJeff Brown * @return True if this route is the default route. 663fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * 664fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * @see MediaRouter#getDefaultRoute 665fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown */ 666fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public boolean isDefault() { 667fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown checkCallingThread(); 668fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return sGlobal.getDefaultRoute() == this; 669fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 670fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 671fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown /** 672fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * Gets a list of {@link MediaControlIntent media control intent} filters that 673fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * describe the capabilities of this route and the media control actions that 674fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * it supports. 675fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * 676fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * @return A list of intent filters that specifies the media control intents that 677fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * this route supports. 678c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 679c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @see MediaControlIntent 680c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @see #supportsControlCategory 681c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @see #supportsControlRequest 682c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 683fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public List<IntentFilter> getControlFilters() { 684fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return mControlFilters; 685c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 686c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 687c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 68828520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown * Returns true if the route supports at least one of the capabilities 68928520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown * described by a media route selector. 69028520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown * 69128520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown * @param selector The selector that specifies the capabilities to check. 69228520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown * @return True if the route supports at least one of the capabilities 69328520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown * described in the media route selector. 69428520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown */ 69511417b1cfde8f1749905f2d735623af9214148afJeff Brown public boolean matchesSelector(MediaRouteSelector selector) { 69628520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown if (selector == null) { 69728520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown throw new IllegalArgumentException("selector must not be null"); 69828520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown } 69928520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown checkCallingThread(); 70011417b1cfde8f1749905f2d735623af9214148afJeff Brown return selector.matchesControlFilters(mControlFilters); 70128520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown } 70228520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown 70328520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown /** 704c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Returns true if the route supports the specified 705c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * {@link MediaControlIntent media control} category. 706c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * <p> 707c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Media control categories describe the capabilities of this route 708c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * such as whether it supports live audio streaming or remote playback. 709c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * </p> 710c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 711c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @param category A {@link MediaControlIntent media control} category 712c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * such as {@link MediaControlIntent#CATEGORY_LIVE_AUDIO}, 713c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * {@link MediaControlIntent#CATEGORY_LIVE_VIDEO}, 714fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * {@link MediaControlIntent#CATEGORY_REMOTE_PLAYBACK}, or a provider-defined 715c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * media control category. 71628520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown * @return True if the route supports the specified intent category. 717c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 718c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @see MediaControlIntent 719fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * @see #getControlFilters 720c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 721c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public boolean supportsControlCategory(String category) { 722c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (category == null) { 723c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown throw new IllegalArgumentException("category must not be null"); 724c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 725fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown checkCallingThread(); 726c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 727fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown int count = mControlFilters.size(); 728fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown for (int i = 0; i < count; i++) { 729fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (mControlFilters.get(i).hasCategory(category)) { 730fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return true; 731fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 732fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 733fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return false; 734c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 735c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 736c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 737c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Returns true if the route supports the specified 738c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * {@link MediaControlIntent media control} request. 739c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * <p> 740c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Media control requests are used to request the route to perform 74143f79f79a5117550a7dfedf9c65124afd163ea43Jeff Brown * actions such as starting remote playback of a media item. 742c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * </p> 743c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 744c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @param intent A {@link MediaControlIntent media control intent}. 745c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @return True if the route can handle the specified intent. 746c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 747c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @see MediaControlIntent 748fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * @see #getControlFilters 749c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 750c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public boolean supportsControlRequest(Intent intent) { 751c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (intent == null) { 752c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown throw new IllegalArgumentException("intent must not be null"); 753c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 754c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown checkCallingThread(); 755c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 756c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown ContentResolver contentResolver = sGlobal.getContentResolver(); 757fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown int count = mControlFilters.size(); 758fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown for (int i = 0; i < count; i++) { 759fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (mControlFilters.get(i).match(contentResolver, intent, true, TAG) >= 0) { 760fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return true; 761fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 762fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 763fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return false; 764c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 765c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 766c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 767c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Sends a {@link MediaControlIntent media control} request to be performed 768c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * asynchronously by the route's destination. 769c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * <p> 770c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Media control requests are used to request the route to perform 77143f79f79a5117550a7dfedf9c65124afd163ea43Jeff Brown * actions such as starting remote playback of a media item. 772c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * </p><p> 773fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * This function may only be called on a selected route. Control requests 774fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * sent to unselected routes will fail. 775c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * </p> 776c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 777c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @param intent A {@link MediaControlIntent media control intent}. 778c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @param callback A {@link ControlRequestCallback} to invoke with the result 779c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * of the request, or null if no result is required. 780c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 781c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @see MediaControlIntent 782c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 783fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public void sendControlRequest(Intent intent, ControlRequestCallback callback) { 784c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (intent == null) { 785c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown throw new IllegalArgumentException("intent must not be null"); 786c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 787c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown checkCallingThread(); 788c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 789fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown sGlobal.sendControlRequest(this, intent, callback); 790c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 791c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 792c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 793c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Gets the type of playback associated with this route. 794c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 795c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @return The type of playback associated with this route: {@link #PLAYBACK_TYPE_LOCAL} 796c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * or {@link #PLAYBACK_TYPE_REMOTE}. 797c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 798c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public int getPlaybackType() { 799c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return mPlaybackType; 800c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 801c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 802c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 803350ba6e4a1b5ec28721a098e50eaf6a508eb28f0Jeff Brown * Gets the audio stream over which the playback associated with this route is performed. 804c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 805c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @return The stream over which the playback associated with this route is performed. 806c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 807c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public int getPlaybackStream() { 808c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return mPlaybackStream; 809c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 810c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 811c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 812c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Gets information about how volume is handled on the route. 813c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 814c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @return How volume is handled on the route: {@link #PLAYBACK_VOLUME_FIXED} 815c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * or {@link #PLAYBACK_VOLUME_VARIABLE}. 816c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 817c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public int getVolumeHandling() { 818c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return mVolumeHandling; 819c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 820c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 821c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 822c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Gets the current volume for this route. Depending on the route, this may only 823c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * be valid if the route is currently selected. 824c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 825c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @return The volume at which the playback associated with this route is performed. 826c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 827c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public int getVolume() { 828c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return mVolume; 829c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 830c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 831c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 832c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Gets the maximum volume at which the playback associated with this route is performed. 833c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 834c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @return The maximum volume at which the playback associated with 835c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * this route is performed. 836c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 837c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public int getVolumeMax() { 838c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return mVolumeMax; 839c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 840c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 841c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 842c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Requests a volume change for this route asynchronously. 843c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * <p> 844c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * This function may only be called on a selected route. It will have 845c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * no effect if the route is currently unselected. 846c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * </p> 847c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 848c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @param volume The new volume value between 0 and {@link #getVolumeMax}. 849c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 850c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public void requestSetVolume(int volume) { 851c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown checkCallingThread(); 852c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown sGlobal.requestSetVolume(this, Math.min(mVolumeMax, Math.max(0, volume))); 853c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 854c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 855c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 856c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Requests an incremental volume update for this route asynchronously. 857c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * <p> 858c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * This function may only be called on a selected route. It will have 859c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * no effect if the route is currently unselected. 860c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * </p> 861c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 862c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @param delta The delta to add to the current volume. 863c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 864c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public void requestUpdateVolume(int delta) { 865c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown checkCallingThread(); 866c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (delta != 0) { 867c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown sGlobal.requestUpdateVolume(this, delta); 868c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 869c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 870c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 871c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 872c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Gets the {@link Display} that should be used by the application to show 873c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * a {@link android.app.Presentation} on an external display when this route is selected. 874c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Depending on the route, this may only be valid if the route is currently 875c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * selected. 876c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * <p> 877c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * The preferred presentation display may change independently of the route 878c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * being selected or unselected. For example, the presentation display 879c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * of the default system route may change when an external HDMI display is connected 880c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * or disconnected even though the route itself has not changed. 881c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * </p><p> 882c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * This method may return null if there is no external display associated with 883c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * the route or if the display is not ready to show UI yet. 884c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * </p><p> 885c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * The application should listen for changes to the presentation display 886c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * using the {@link Callback#onRoutePresentationDisplayChanged} callback and 887c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * show or dismiss its {@link android.app.Presentation} accordingly when the display 888c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * becomes available or is removed. 889c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * </p><p> 890c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * This method only makes sense for 891c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * {@link MediaControlIntent#CATEGORY_LIVE_VIDEO live video} routes. 892c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * </p> 893c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 894c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @return The preferred presentation display to use when this route is 895c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * selected or null if none. 896c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 897c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @see MediaControlIntent#CATEGORY_LIVE_VIDEO 898c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @see android.app.Presentation 899c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 900c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public Display getPresentationDisplay() { 901fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown checkCallingThread(); 902c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (mPresentationDisplayId >= 0 && mPresentationDisplay == null) { 903c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown mPresentationDisplay = sGlobal.getDisplay(mPresentationDisplayId); 904c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 905c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return mPresentationDisplay; 906c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 907c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 908c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 909c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Gets a collection of extra properties about this route that were supplied 910c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * by its media route provider, or null if none. 911c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 912c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public Bundle getExtras() { 913c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return mExtras; 914c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 915c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 916fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown /** 917fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * Selects this media route. 918fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown */ 919fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public void select() { 920fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown checkCallingThread(); 921fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown sGlobal.selectRoute(this); 922fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 923fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 924c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown @Override 925c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public String toString() { 926c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return "MediaRouter.RouteInfo{ name=" + mName 927d63957d28aaabcec588b8cde12eac16414783aebJeff Brown + ", description=" + mDescription 928c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown + ", enabled=" + mEnabled 92911417b1cfde8f1749905f2d735623af9214148afJeff Brown + ", connecting=" + mConnecting 930c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown + ", playbackType=" + mPlaybackType 931c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown + ", playbackStream=" + mPlaybackStream 932c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown + ", volumeHandling=" + mVolumeHandling 933c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown + ", volume=" + mVolume 934c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown + ", volumeMax=" + mVolumeMax 935c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown + ", presentationDisplayId=" + mPresentationDisplayId 936c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown + ", extras=" + mExtras 937fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown + ", providerPackageName=" + mProvider.getPackageName() 938fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown + " }"; 939fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 940fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 94111417b1cfde8f1749905f2d735623af9214148afJeff Brown int updateDescriptor(MediaRouteDescriptor descriptor) { 942fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown int changes = 0; 943fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (mDescriptor != descriptor) { 944fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mDescriptor = descriptor; 945fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (descriptor != null) { 946fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (!equal(mName, descriptor.getName())) { 947fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mName = descriptor.getName(); 948fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown changes |= CHANGE_GENERAL; 949fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 950d63957d28aaabcec588b8cde12eac16414783aebJeff Brown if (!equal(mDescription, descriptor.getDescription())) { 951d63957d28aaabcec588b8cde12eac16414783aebJeff Brown mDescription = descriptor.getDescription(); 952fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown changes |= CHANGE_GENERAL; 953fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 954fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (mEnabled != descriptor.isEnabled()) { 955fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mEnabled = descriptor.isEnabled(); 956fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown changes |= CHANGE_GENERAL; 957fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 95811417b1cfde8f1749905f2d735623af9214148afJeff Brown if (mConnecting != descriptor.isConnecting()) { 95911417b1cfde8f1749905f2d735623af9214148afJeff Brown mConnecting = descriptor.isConnecting(); 96011417b1cfde8f1749905f2d735623af9214148afJeff Brown changes |= CHANGE_GENERAL; 96111417b1cfde8f1749905f2d735623af9214148afJeff Brown } 96211417b1cfde8f1749905f2d735623af9214148afJeff Brown if (!mControlFilters.equals(descriptor.getControlFilters())) { 963fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mControlFilters.clear(); 96411417b1cfde8f1749905f2d735623af9214148afJeff Brown mControlFilters.addAll(descriptor.getControlFilters()); 965fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown changes |= CHANGE_GENERAL; 966fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 967fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (mPlaybackType != descriptor.getPlaybackType()) { 968fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mPlaybackType = descriptor.getPlaybackType(); 969fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown changes |= CHANGE_GENERAL; 970fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 971fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (mPlaybackStream != descriptor.getPlaybackStream()) { 972fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mPlaybackStream = descriptor.getPlaybackStream(); 973fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown changes |= CHANGE_GENERAL; 974fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 975fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (mVolumeHandling != descriptor.getVolumeHandling()) { 976fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mVolumeHandling = descriptor.getVolumeHandling(); 977fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown changes |= CHANGE_GENERAL | CHANGE_VOLUME; 978fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 979fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (mVolume != descriptor.getVolume()) { 980fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mVolume = descriptor.getVolume(); 981fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown changes |= CHANGE_GENERAL | CHANGE_VOLUME; 982fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 983fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (mVolumeMax != descriptor.getVolumeMax()) { 984fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mVolumeMax = descriptor.getVolumeMax(); 985fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown changes |= CHANGE_GENERAL | CHANGE_VOLUME; 986fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 987fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (mPresentationDisplayId != descriptor.getPresentationDisplayId()) { 988fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mPresentationDisplayId = descriptor.getPresentationDisplayId(); 989fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mPresentationDisplay = null; 990fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown changes |= CHANGE_GENERAL | CHANGE_PRESENTATION_DISPLAY; 991fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 992fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (!equal(mExtras, descriptor.getExtras())) { 993fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mExtras = descriptor.getExtras(); 994fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown changes |= CHANGE_GENERAL; 995fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 996fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 997fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 998fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return changes; 999fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 1000fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 1001fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown String getDescriptorId() { 1002fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return mDescriptorId; 1003fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 1004fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 1005fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown MediaRouteProvider getProviderInstance() { 1006fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return mProvider.getProviderInstance(); 1007fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 1008fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 1009fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 1010fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown /** 1011fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * Provides information about a media route provider. 1012fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * <p> 1013fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * This object may be used to determine which media route provider has 1014fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * published a particular route. 1015fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * </p> 1016fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown */ 1017fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public static final class ProviderInfo { 1018fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private final MediaRouteProvider mProviderInstance; 1019fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private final ArrayList<RouteInfo> mRoutes = new ArrayList<RouteInfo>(); 102011417b1cfde8f1749905f2d735623af9214148afJeff Brown private final ArrayList<IntentFilter> mDiscoverableControlFilters = 102111417b1cfde8f1749905f2d735623af9214148afJeff Brown new ArrayList<IntentFilter>(); 1022fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 1023fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private final ProviderMetadata mMetadata; 102411417b1cfde8f1749905f2d735623af9214148afJeff Brown private MediaRouteProviderDescriptor mDescriptor; 1025fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private Resources mResources; 1026fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private boolean mResourcesNotAvailable; 1027fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 1028fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown ProviderInfo(MediaRouteProvider provider) { 1029fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mProviderInstance = provider; 1030fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mMetadata = provider.getMetadata(); 1031fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 1032fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 1033fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown /** 1034fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * Gets the provider's underlying {@link MediaRouteProvider} instance. 1035fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown */ 1036fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public MediaRouteProvider getProviderInstance() { 1037fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown checkCallingThread(); 1038fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return mProviderInstance; 1039fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 1040fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 1041fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown /** 1042fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * Gets the package name of the media route provider service. 1043fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown */ 1044fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public String getPackageName() { 1045fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return mMetadata.getPackageName(); 1046fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 1047fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 1048fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown /** 1049fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * Gets the {@link MediaRouter.RouteInfo routes} published by this route provider. 1050fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown */ 1051fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public List<RouteInfo> getRoutes() { 1052fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown checkCallingThread(); 1053fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return mRoutes; 1054fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 1055fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 105628520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown /** 105728520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown * Returns true if the provider requires active scans to discover routes. 105811417b1cfde8f1749905f2d735623af9214148afJeff Brown * <p> 105911417b1cfde8f1749905f2d735623af9214148afJeff Brown * To provide the best user experience, a media route provider should passively 106011417b1cfde8f1749905f2d735623af9214148afJeff Brown * discover and publish changes to route descriptors in the background. 106111417b1cfde8f1749905f2d735623af9214148afJeff Brown * However, for some providers, scanning for routes may use a significant 106211417b1cfde8f1749905f2d735623af9214148afJeff Brown * amount of power or may interfere with wireless network connectivity. 106311417b1cfde8f1749905f2d735623af9214148afJeff Brown * If this is the case, then the provider will indicate that it requires 106411417b1cfde8f1749905f2d735623af9214148afJeff Brown * active scans to discover routes by setting this flag. Active scans 106511417b1cfde8f1749905f2d735623af9214148afJeff Brown * will be performed when the user opens the route chooser dialog. 106611417b1cfde8f1749905f2d735623af9214148afJeff Brown * </p> 106728520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown */ 106828520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown public boolean isActiveScanRequired() { 106928520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown checkCallingThread(); 107028520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown return mDescriptor != null && mDescriptor.isActiveScanRequired(); 107128520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown } 107228520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown 107311417b1cfde8f1749905f2d735623af9214148afJeff Brown /** 107411417b1cfde8f1749905f2d735623af9214148afJeff Brown * Gets a list of {@link MediaControlIntent media route control filters} that 107511417b1cfde8f1749905f2d735623af9214148afJeff Brown * describe the union of capabilities of all routes that this provider can 107611417b1cfde8f1749905f2d735623af9214148afJeff Brown * possibly discover. 107711417b1cfde8f1749905f2d735623af9214148afJeff Brown * <p> 107811417b1cfde8f1749905f2d735623af9214148afJeff Brown * Because a route provider may not know what to look for until an 107911417b1cfde8f1749905f2d735623af9214148afJeff Brown * application actually asks for it, the contents of the discoverable control 108011417b1cfde8f1749905f2d735623af9214148afJeff Brown * filter list may change depending on the route selectors that applications have 108111417b1cfde8f1749905f2d735623af9214148afJeff Brown * actually specified when {@link MediaRouter#addCallback registering callbacks} 108211417b1cfde8f1749905f2d735623af9214148afJeff Brown * on the media router to discover routes. 108311417b1cfde8f1749905f2d735623af9214148afJeff Brown * </p> 108411417b1cfde8f1749905f2d735623af9214148afJeff Brown */ 108511417b1cfde8f1749905f2d735623af9214148afJeff Brown public List<IntentFilter> getDiscoverableControlFilters() { 108611417b1cfde8f1749905f2d735623af9214148afJeff Brown checkCallingThread(); 108711417b1cfde8f1749905f2d735623af9214148afJeff Brown return mDiscoverableControlFilters; 108811417b1cfde8f1749905f2d735623af9214148afJeff Brown } 108911417b1cfde8f1749905f2d735623af9214148afJeff Brown 1090fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown Resources getResources() { 1091fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (mResources == null && !mResourcesNotAvailable) { 1092fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown String packageName = getPackageName(); 1093fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown Context context = sGlobal.getProviderContext(packageName); 1094fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (context != null) { 1095fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mResources = context.getResources(); 1096fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } else { 1097fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown Log.w(TAG, "Unable to obtain resources for route provider package: " 1098fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown + packageName); 1099fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mResourcesNotAvailable = true; 1100fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 1101fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 1102fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return mResources; 1103fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 1104fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 110511417b1cfde8f1749905f2d735623af9214148afJeff Brown boolean updateDescriptor(MediaRouteProviderDescriptor descriptor) { 1106fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (mDescriptor != descriptor) { 1107fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mDescriptor = descriptor; 11082ef36d857302c5cd738c7c8bdec53d31feebebbaJeff Brown if (descriptor != null) { 11092ef36d857302c5cd738c7c8bdec53d31feebebbaJeff Brown if (!mDiscoverableControlFilters.equals( 11102ef36d857302c5cd738c7c8bdec53d31feebebbaJeff Brown descriptor.getDiscoverableControlFilters())) { 11112ef36d857302c5cd738c7c8bdec53d31feebebbaJeff Brown mDiscoverableControlFilters.clear(); 11123d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown mDiscoverableControlFilters.addAll( 11133d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown descriptor.getDiscoverableControlFilters()); 11142ef36d857302c5cd738c7c8bdec53d31feebebbaJeff Brown } 111511417b1cfde8f1749905f2d735623af9214148afJeff Brown } 1116fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return true; 1117fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 1118fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return false; 1119fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 1120fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 1121fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown int findRouteByDescriptorId(String id) { 1122fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown final int count = mRoutes.size(); 1123fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown for (int i = 0; i < count; i++) { 1124fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (mRoutes.get(i).mDescriptorId.equals(id)) { 1125fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return i; 1126fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 1127fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 1128fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return -1; 1129fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 1130fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 1131fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown @Override 1132fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public String toString() { 1133fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return "MediaRouter.RouteProviderInfo{ packageName=" + getPackageName() 113411417b1cfde8f1749905f2d735623af9214148afJeff Brown + ", isActiveScanRequired=" + isActiveScanRequired() 1135c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown + " }"; 1136c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1137c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1138c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1139c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 1140c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Interface for receiving events about media routing changes. 1141c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * All methods of this interface will be called from the application's main thread. 1142c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * <p> 1143c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * A Callback will only receive events relevant to routes that the callback 114411417b1cfde8f1749905f2d735623af9214148afJeff Brown * was registered for unless the {@link MediaRouter#CALLBACK_FLAG_UNFILTERED_EVENTS} 114511417b1cfde8f1749905f2d735623af9214148afJeff Brown * flag was specified in {@link MediaRouter#addCallback(MediaRouteSelector, Callback, int)}. 1146c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * </p> 1147c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 114811417b1cfde8f1749905f2d735623af9214148afJeff Brown * @see MediaRouter#addCallback(MediaRouteSelector, Callback, int) 1149c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @see MediaRouter#removeCallback(Callback) 1150c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 1151c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public static abstract class Callback { 1152c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 1153fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * Called when the supplied media route becomes selected as the active route. 1154c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 1155fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * @param router The media router reporting the event. 1156c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @param route The route that has been selected. 1157c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 1158c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public void onRouteSelected(MediaRouter router, RouteInfo route) { 1159c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1160c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1161c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 1162fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * Called when the supplied media route becomes unselected as the active route. 1163c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 1164fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * @param router The media router reporting the event. 1165c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @param route The route that has been unselected. 1166c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 1167c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public void onRouteUnselected(MediaRouter router, RouteInfo route) { 1168c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1169c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1170c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 1171fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * Called when a media route has been added. 1172c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 1173fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * @param router The media router reporting the event. 1174c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @param route The route that has become available for use. 1175c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 1176c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public void onRouteAdded(MediaRouter router, RouteInfo route) { 1177c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1178c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1179c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 1180fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * Called when a media route has been removed. 1181c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 1182fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * @param router The media router reporting the event. 1183c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @param route The route that has been removed from availability. 1184c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 1185c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public void onRouteRemoved(MediaRouter router, RouteInfo route) { 1186c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1187c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1188c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 1189fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * Called when a property of the indicated media route has changed. 1190c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 1191fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * @param router The media router reporting the event. 1192c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @param route The route that was changed. 1193c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 1194c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public void onRouteChanged(MediaRouter router, RouteInfo route) { 1195c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1196c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1197c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 1198fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * Called when a media route's volume changes. 1199c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 1200fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * @param router The media router reporting the event. 1201c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @param route The route whose volume changed. 1202c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 1203c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public void onRouteVolumeChanged(MediaRouter router, RouteInfo route) { 1204c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1205c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1206c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 1207fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * Called when a media route's presentation display changes. 1208c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * <p> 1209c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * This method is called whenever the route's presentation display becomes 1210fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * available, is removed or has changes to some of its properties (such as its size). 1211c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * </p> 1212c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 1213fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * @param router The media router reporting the event. 1214c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @param route The route whose presentation display changed. 1215c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 1216c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @see RouteInfo#getPresentationDisplay() 1217c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 1218c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public void onRoutePresentationDisplayChanged(MediaRouter router, RouteInfo route) { 1219c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1220fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 1221fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown /** 1222fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * Called when a media route provider has been added. 1223fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * 1224fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * @param router The media router reporting the event. 1225fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * @param provider The provider that has become available for use. 1226fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown */ 1227fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public void onProviderAdded(MediaRouter router, ProviderInfo provider) { 1228fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 1229fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 1230fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown /** 1231fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * Called when a media route provider has been removed. 1232fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * 1233fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * @param router The media router reporting the event. 1234fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * @param provider The provider that has been removed from availability. 1235fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown */ 1236fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public void onProviderRemoved(MediaRouter router, ProviderInfo provider) { 1237fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 123811417b1cfde8f1749905f2d735623af9214148afJeff Brown 123911417b1cfde8f1749905f2d735623af9214148afJeff Brown /** 124011417b1cfde8f1749905f2d735623af9214148afJeff Brown * Called when a property of the indicated media route provider has changed. 124111417b1cfde8f1749905f2d735623af9214148afJeff Brown * 124211417b1cfde8f1749905f2d735623af9214148afJeff Brown * @param router The media router reporting the event. 124311417b1cfde8f1749905f2d735623af9214148afJeff Brown * @param provider The provider that was changed. 124411417b1cfde8f1749905f2d735623af9214148afJeff Brown */ 124511417b1cfde8f1749905f2d735623af9214148afJeff Brown public void onProviderChanged(MediaRouter router, ProviderInfo provider) { 124611417b1cfde8f1749905f2d735623af9214148afJeff Brown } 1247c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1248c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1249c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 1250c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Callback which is invoked with the result of a media control request. 1251c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 1252c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @see RouteInfo#sendControlRequest 1253c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 1254fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public static abstract class ControlRequestCallback { 1255c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 12563d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown * Called when a media control request succeeds. 12573d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown * 12583d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown * @param data Result data, or null if none. 12593d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown * Contents depend on the {@link MediaControlIntent media control action}. 1260c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 12613d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown public void onResult(Bundle data) { 12623d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown } 1263c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1264c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 12653d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown * Called when a media control request fails. 1266c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 12673d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown * @param error A localized error message which may be shown to the user, or null 12683d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown * if the cause of the error is unclear. 12693d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown * @param data Error data, or null if none. 12703d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown * Contents depend on the {@link MediaControlIntent media control action}. 1271c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 12723d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown public void onError(String error, Bundle data) { 1273c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1274c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1275c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 127611417b1cfde8f1749905f2d735623af9214148afJeff Brown private static final class CallbackRecord { 127711417b1cfde8f1749905f2d735623af9214148afJeff Brown public final Callback mCallback; 127811417b1cfde8f1749905f2d735623af9214148afJeff Brown public MediaRouteSelector mSelector; 127911417b1cfde8f1749905f2d735623af9214148afJeff Brown public int mFlags; 128011417b1cfde8f1749905f2d735623af9214148afJeff Brown 128111417b1cfde8f1749905f2d735623af9214148afJeff Brown public CallbackRecord(Callback callback) { 128211417b1cfde8f1749905f2d735623af9214148afJeff Brown mCallback = callback; 128311417b1cfde8f1749905f2d735623af9214148afJeff Brown mSelector = MediaRouteSelector.EMPTY; 128411417b1cfde8f1749905f2d735623af9214148afJeff Brown } 128511417b1cfde8f1749905f2d735623af9214148afJeff Brown 128611417b1cfde8f1749905f2d735623af9214148afJeff Brown public boolean filterRouteEvent(RouteInfo route) { 128711417b1cfde8f1749905f2d735623af9214148afJeff Brown return (mFlags & CALLBACK_FLAG_UNFILTERED_EVENTS) != 0 128811417b1cfde8f1749905f2d735623af9214148afJeff Brown || route.matchesSelector(mSelector); 128911417b1cfde8f1749905f2d735623af9214148afJeff Brown } 129011417b1cfde8f1749905f2d735623af9214148afJeff Brown } 129111417b1cfde8f1749905f2d735623af9214148afJeff Brown 1292c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 1293c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Global state for the media router. 1294c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * <p> 1295c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Media routes and media route providers are global to the process; their 1296c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * state and the bulk of the media router implementation lives here. 1297c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * </p> 1298c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 1299c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown private static final class GlobalMediaRouter implements SystemMediaRouteProvider.SyncCallback { 1300c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown private final Context mApplicationContext; 1301fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private final MediaRouter mApplicationRouter; 1302c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown private final WeakHashMap<Context, MediaRouter> mRouters = 1303c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown new WeakHashMap<Context, MediaRouter>(); 1304c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown private final ArrayList<RouteInfo> mRoutes = new ArrayList<RouteInfo>(); 1305fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private final ArrayList<ProviderInfo> mProviders = 1306fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown new ArrayList<ProviderInfo>(); 1307c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown private final ProviderCallback mProviderCallback = new ProviderCallback(); 1308c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown private final CallbackHandler mCallbackHandler = new CallbackHandler(); 1309c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown private final DisplayManagerCompat mDisplayManager; 1310c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown private final SystemMediaRouteProvider mSystemProvider; 1311c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1312fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private RegisteredMediaRouteProviderWatcher mRegisteredProviderWatcher; 1313c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown private RouteInfo mDefaultRoute; 1314c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown private RouteInfo mSelectedRoute; 1315c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown private MediaRouteProvider.RouteController mSelectedRouteController; 131611417b1cfde8f1749905f2d735623af9214148afJeff Brown private MediaRouteDiscoveryRequest mDiscoveryRequest; 1317c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1318c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown GlobalMediaRouter(Context applicationContext) { 1319c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown mApplicationContext = applicationContext; 1320c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown mDisplayManager = DisplayManagerCompat.getInstance(applicationContext); 1321fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mApplicationRouter = getRouter(applicationContext); 1322fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 1323fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown // Add the system media route provider for interoperating with 1324fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown // the framework media router. This one is special and receives 1325fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown // synchronization messages from the media router. 1326c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown mSystemProvider = SystemMediaRouteProvider.obtain(applicationContext, this); 1327fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown addProvider(mSystemProvider); 1328fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 1329fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 1330fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public void start() { 1331fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown // Start watching for routes published by registered media route 1332fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown // provider services. 1333fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mRegisteredProviderWatcher = new RegisteredMediaRouteProviderWatcher( 1334fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mApplicationContext, mApplicationRouter); 1335fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mRegisteredProviderWatcher.start(); 1336c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1337c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1338c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public MediaRouter getRouter(Context context) { 1339c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown MediaRouter router = mRouters.get(context); 1340c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (router == null) { 1341c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown router = new MediaRouter(context); 1342c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown mRouters.put(context, router); 1343c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1344c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return router; 1345c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1346c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1347c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public ContentResolver getContentResolver() { 1348c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return mApplicationContext.getContentResolver(); 1349c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1350c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1351fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public Context getProviderContext(String packageName) { 1352fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (packageName.equals(SystemMediaRouteProvider.PACKAGE_NAME)) { 1353fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return mApplicationContext; 1354fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 1355fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown try { 1356fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return mApplicationContext.createPackageContext( 1357fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown packageName, Context.CONTEXT_RESTRICTED); 1358fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } catch (NameNotFoundException ex) { 1359fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return null; 1360fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 1361fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 1362fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 1363c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public Display getDisplay(int displayId) { 1364c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return mDisplayManager.getDisplay(displayId); 1365c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1366c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1367fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public void sendControlRequest(RouteInfo route, 1368c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown Intent intent, ControlRequestCallback callback) { 1369c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (route == mSelectedRoute && mSelectedRouteController != null) { 1370129abf73ce9be1bc172b945263c7975ad1a3006fJeff Brown if (mSelectedRouteController.onControlRequest(intent, callback)) { 1371fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return; 1372fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 1373fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 1374fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (callback != null) { 13753d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown callback.onError(null, null); 1376c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1377c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1378c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1379c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public void requestSetVolume(RouteInfo route, int volume) { 1380c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (route == mSelectedRoute && mSelectedRouteController != null) { 1381129abf73ce9be1bc172b945263c7975ad1a3006fJeff Brown mSelectedRouteController.onSetVolume(volume); 1382c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1383c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1384c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1385c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public void requestUpdateVolume(RouteInfo route, int delta) { 1386c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (route == mSelectedRoute && mSelectedRouteController != null) { 1387129abf73ce9be1bc172b945263c7975ad1a3006fJeff Brown mSelectedRouteController.onUpdateVolume(delta); 1388c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1389c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1390c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1391c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public List<RouteInfo> getRoutes() { 1392c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return mRoutes; 1393c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1394c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1395fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public List<ProviderInfo> getProviders() { 1396fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return mProviders; 1397fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 1398fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 1399c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public RouteInfo getDefaultRoute() { 1400c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (mDefaultRoute == null) { 1401c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown // This should never happen once the media router has been fully 1402c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown // initialized but it is good to check for the error in case there 1403c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown // is a bug in provider initialization. 1404c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown throw new IllegalStateException("There is no default route. " 1405c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown + "The media router has not yet been fully initialized."); 1406c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1407c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return mDefaultRoute; 1408c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1409c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1410c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public RouteInfo getSelectedRoute() { 1411c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (mSelectedRoute == null) { 1412c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown // This should never happen once the media router has been fully 1413c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown // initialized but it is good to check for the error in case there 1414c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown // is a bug in provider initialization. 1415c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown throw new IllegalStateException("There is no currently selected route. " 1416c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown + "The media router has not yet been fully initialized."); 1417c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1418c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return mSelectedRoute; 1419c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1420c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1421c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public void selectRoute(RouteInfo route) { 1422c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (!mRoutes.contains(route)) { 1423c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown Log.w(TAG, "Ignoring attempt to select removed route: " + route); 1424c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return; 1425c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1426c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (!route.mEnabled) { 1427c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown Log.w(TAG, "Ignoring attempt to select disabled route: " + route); 1428c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return; 1429c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1430c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1431c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown setSelectedRouteInternal(route); 1432c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1433c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 143411417b1cfde8f1749905f2d735623af9214148afJeff Brown public boolean isRouteAvailable(MediaRouteSelector selector, int flags) { 143511417b1cfde8f1749905f2d735623af9214148afJeff Brown // Check whether any existing routes match the selector. 143611417b1cfde8f1749905f2d735623af9214148afJeff Brown final int routeCount = mRoutes.size(); 143711417b1cfde8f1749905f2d735623af9214148afJeff Brown for (int i = 0; i < routeCount; i++) { 143811417b1cfde8f1749905f2d735623af9214148afJeff Brown RouteInfo route = mRoutes.get(i); 143911417b1cfde8f1749905f2d735623af9214148afJeff Brown if ((flags & AVAILABILITY_FLAG_IGNORE_DEFAULT_ROUTE) != 0 144011417b1cfde8f1749905f2d735623af9214148afJeff Brown && route.isDefault()) { 144111417b1cfde8f1749905f2d735623af9214148afJeff Brown continue; 144211417b1cfde8f1749905f2d735623af9214148afJeff Brown } 144311417b1cfde8f1749905f2d735623af9214148afJeff Brown if (route.matchesSelector(selector)) { 144411417b1cfde8f1749905f2d735623af9214148afJeff Brown return true; 144511417b1cfde8f1749905f2d735623af9214148afJeff Brown } 144611417b1cfde8f1749905f2d735623af9214148afJeff Brown } 144711417b1cfde8f1749905f2d735623af9214148afJeff Brown 144811417b1cfde8f1749905f2d735623af9214148afJeff Brown // Check whether any provider could possibly discover a matching route 144911417b1cfde8f1749905f2d735623af9214148afJeff Brown // if a required active scan were performed. 145011417b1cfde8f1749905f2d735623af9214148afJeff Brown if ((flags & AVAILABILITY_FLAG_CONSIDER_ACTIVE_SCAN) != 0) { 145111417b1cfde8f1749905f2d735623af9214148afJeff Brown final int providerCount = mProviders.size(); 145211417b1cfde8f1749905f2d735623af9214148afJeff Brown for (int i = 0; i < providerCount; i++) { 145311417b1cfde8f1749905f2d735623af9214148afJeff Brown ProviderInfo provider = mProviders.get(i); 145411417b1cfde8f1749905f2d735623af9214148afJeff Brown if (provider.isActiveScanRequired() && selector.matchesControlFilters( 145511417b1cfde8f1749905f2d735623af9214148afJeff Brown provider.getDiscoverableControlFilters())) { 145611417b1cfde8f1749905f2d735623af9214148afJeff Brown return true; 145711417b1cfde8f1749905f2d735623af9214148afJeff Brown } 145811417b1cfde8f1749905f2d735623af9214148afJeff Brown } 145911417b1cfde8f1749905f2d735623af9214148afJeff Brown } 146011417b1cfde8f1749905f2d735623af9214148afJeff Brown 146111417b1cfde8f1749905f2d735623af9214148afJeff Brown // It doesn't look like we can find a matching route right now. 146211417b1cfde8f1749905f2d735623af9214148afJeff Brown return false; 146311417b1cfde8f1749905f2d735623af9214148afJeff Brown } 146411417b1cfde8f1749905f2d735623af9214148afJeff Brown 146511417b1cfde8f1749905f2d735623af9214148afJeff Brown public void updateDiscoveryRequest() { 146611417b1cfde8f1749905f2d735623af9214148afJeff Brown // Combine all of the callback selectors and active scan flags. 146711417b1cfde8f1749905f2d735623af9214148afJeff Brown boolean activeScan = false; 146811417b1cfde8f1749905f2d735623af9214148afJeff Brown MediaRouteSelector.Builder builder = new MediaRouteSelector.Builder(); 146928520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown for (MediaRouter router : mRouters.values()) { 147011417b1cfde8f1749905f2d735623af9214148afJeff Brown final int count = router.mCallbackRecords.size(); 147111417b1cfde8f1749905f2d735623af9214148afJeff Brown for (int i = 0; i < count; i++) { 147211417b1cfde8f1749905f2d735623af9214148afJeff Brown CallbackRecord callback = router.mCallbackRecords.get(i); 147311417b1cfde8f1749905f2d735623af9214148afJeff Brown builder.addSelector(callback.mSelector); 147411417b1cfde8f1749905f2d735623af9214148afJeff Brown if ((callback.mFlags & CALLBACK_FLAG_ACTIVE_SCAN) != 0) { 147511417b1cfde8f1749905f2d735623af9214148afJeff Brown activeScan = true; 147611417b1cfde8f1749905f2d735623af9214148afJeff Brown } 147711417b1cfde8f1749905f2d735623af9214148afJeff Brown } 147811417b1cfde8f1749905f2d735623af9214148afJeff Brown } 147911417b1cfde8f1749905f2d735623af9214148afJeff Brown MediaRouteSelector selector = builder.build(); 148011417b1cfde8f1749905f2d735623af9214148afJeff Brown 148111417b1cfde8f1749905f2d735623af9214148afJeff Brown // Create a new discovery request. 148211417b1cfde8f1749905f2d735623af9214148afJeff Brown if (mDiscoveryRequest != null 148311417b1cfde8f1749905f2d735623af9214148afJeff Brown && mDiscoveryRequest.getSelector().equals(selector) 148411417b1cfde8f1749905f2d735623af9214148afJeff Brown && mDiscoveryRequest.isActiveScan() == activeScan) { 148511417b1cfde8f1749905f2d735623af9214148afJeff Brown return; // no change 148611417b1cfde8f1749905f2d735623af9214148afJeff Brown } 148711417b1cfde8f1749905f2d735623af9214148afJeff Brown if (selector.isEmpty() && !activeScan) { 148811417b1cfde8f1749905f2d735623af9214148afJeff Brown // Discovery is not needed. 148911417b1cfde8f1749905f2d735623af9214148afJeff Brown if (mDiscoveryRequest == null) { 149011417b1cfde8f1749905f2d735623af9214148afJeff Brown return; // no change 149111417b1cfde8f1749905f2d735623af9214148afJeff Brown } 149211417b1cfde8f1749905f2d735623af9214148afJeff Brown mDiscoveryRequest = null; 149311417b1cfde8f1749905f2d735623af9214148afJeff Brown } else { 149411417b1cfde8f1749905f2d735623af9214148afJeff Brown // Discovery is needed. 149511417b1cfde8f1749905f2d735623af9214148afJeff Brown mDiscoveryRequest = new MediaRouteDiscoveryRequest(selector, activeScan); 149611417b1cfde8f1749905f2d735623af9214148afJeff Brown } 149711417b1cfde8f1749905f2d735623af9214148afJeff Brown if (DEBUG) { 149811417b1cfde8f1749905f2d735623af9214148afJeff Brown Log.d(TAG, "Updated discovery request: " + mDiscoveryRequest); 149911417b1cfde8f1749905f2d735623af9214148afJeff Brown } 150011417b1cfde8f1749905f2d735623af9214148afJeff Brown 150111417b1cfde8f1749905f2d735623af9214148afJeff Brown // Notify providers. 150211417b1cfde8f1749905f2d735623af9214148afJeff Brown final int providerCount = mProviders.size(); 150311417b1cfde8f1749905f2d735623af9214148afJeff Brown for (int i = 0; i < providerCount; i++) { 150411417b1cfde8f1749905f2d735623af9214148afJeff Brown mProviders.get(i).mProviderInstance.setDiscoveryRequest(mDiscoveryRequest); 150528520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown } 150628520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown } 150728520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown 1508fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public void addProvider(MediaRouteProvider providerInstance) { 1509fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown int index = findProviderInfo(providerInstance); 1510c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (index < 0) { 1511c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown // 1. Add the provider to the list. 1512fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown ProviderInfo provider = new ProviderInfo(providerInstance); 1513fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mProviders.add(provider); 151411417b1cfde8f1749905f2d735623af9214148afJeff Brown if (DEBUG) { 151511417b1cfde8f1749905f2d735623af9214148afJeff Brown Log.d(TAG, "Provider added: " + provider); 151611417b1cfde8f1749905f2d735623af9214148afJeff Brown } 1517fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mCallbackHandler.post(CallbackHandler.MSG_PROVIDER_ADDED, provider); 1518c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown // 2. Create the provider's contents. 1519fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown updateProviderContents(provider, providerInstance.getDescriptor()); 1520c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown // 3. Register the provider callback. 152111417b1cfde8f1749905f2d735623af9214148afJeff Brown providerInstance.setCallback(mProviderCallback); 152211417b1cfde8f1749905f2d735623af9214148afJeff Brown // 4. Set the discovery request. 152311417b1cfde8f1749905f2d735623af9214148afJeff Brown providerInstance.setDiscoveryRequest(mDiscoveryRequest); 1524c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1525c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1526c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1527fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public void removeProvider(MediaRouteProvider providerInstance) { 1528fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown int index = findProviderInfo(providerInstance); 1529c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (index >= 0) { 153011417b1cfde8f1749905f2d735623af9214148afJeff Brown // 1. Unregister the provider callback. 153111417b1cfde8f1749905f2d735623af9214148afJeff Brown providerInstance.setCallback(null); 153211417b1cfde8f1749905f2d735623af9214148afJeff Brown // 2. Clear the discovery request. 153311417b1cfde8f1749905f2d735623af9214148afJeff Brown providerInstance.setDiscoveryRequest(null); 153428520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown // 3. Delete the provider's contents. 1535fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown ProviderInfo provider = mProviders.get(index); 1536fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown updateProviderContents(provider, null); 153728520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown // 4. Remove the provider from the list. 153811417b1cfde8f1749905f2d735623af9214148afJeff Brown if (DEBUG) { 153911417b1cfde8f1749905f2d735623af9214148afJeff Brown Log.d(TAG, "Provider removed: " + provider); 154011417b1cfde8f1749905f2d735623af9214148afJeff Brown } 1541fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mCallbackHandler.post(CallbackHandler.MSG_PROVIDER_REMOVED, provider); 1542fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mProviders.remove(index); 1543c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1544c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1545c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1546fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private void updateProviderDescriptor(MediaRouteProvider providerInstance, 154711417b1cfde8f1749905f2d735623af9214148afJeff Brown MediaRouteProviderDescriptor descriptor) { 1548fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown int index = findProviderInfo(providerInstance); 1549c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (index >= 0) { 1550fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown // Update the provider's contents. 1551fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown ProviderInfo provider = mProviders.get(index); 1552fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown updateProviderContents(provider, descriptor); 1553c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1554c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1555c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1556fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private int findProviderInfo(MediaRouteProvider providerInstance) { 1557fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown final int count = mProviders.size(); 1558c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown for (int i = 0; i < count; i++) { 1559fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (mProviders.get(i).mProviderInstance == providerInstance) { 1560c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return i; 1561c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1562c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1563c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return -1; 1564c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1565c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1566fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private void updateProviderContents(ProviderInfo provider, 156711417b1cfde8f1749905f2d735623af9214148afJeff Brown MediaRouteProviderDescriptor providerDescriptor) { 1568fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (provider.updateDescriptor(providerDescriptor)) { 1569c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown // Update all existing routes and reorder them to match 1570c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown // the order of their descriptors. 1571c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown int targetIndex = 0; 1572c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (providerDescriptor != null) { 1573fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (providerDescriptor.isValid()) { 157411417b1cfde8f1749905f2d735623af9214148afJeff Brown final List<MediaRouteDescriptor> routeDescriptors = 157511417b1cfde8f1749905f2d735623af9214148afJeff Brown providerDescriptor.getRoutes(); 157611417b1cfde8f1749905f2d735623af9214148afJeff Brown final int routeCount = routeDescriptors.size(); 157711417b1cfde8f1749905f2d735623af9214148afJeff Brown for (int i = 0; i < routeCount; i++) { 157811417b1cfde8f1749905f2d735623af9214148afJeff Brown final MediaRouteDescriptor routeDescriptor = routeDescriptors.get(i); 1579c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown final String id = routeDescriptor.getId(); 1580fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown final int sourceIndex = provider.findRouteByDescriptorId(id); 1581c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (sourceIndex < 0) { 1582c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown // 1. Add the route to the list. 1583fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown RouteInfo route = new RouteInfo(provider, id); 1584fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown provider.mRoutes.add(targetIndex++, route); 1585c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown mRoutes.add(route); 1586c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown // 2. Create the route's contents. 1587c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown route.updateDescriptor(routeDescriptor); 1588fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown // 3. Notify clients about addition. 158911417b1cfde8f1749905f2d735623af9214148afJeff Brown if (DEBUG) { 159011417b1cfde8f1749905f2d735623af9214148afJeff Brown Log.d(TAG, "Route added: " + route); 159111417b1cfde8f1749905f2d735623af9214148afJeff Brown } 1592c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown mCallbackHandler.post(CallbackHandler.MSG_ROUTE_ADDED, route); 1593fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } else if (sourceIndex < targetIndex) { 1594fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown Log.w(TAG, "Ignoring route descriptor with duplicate id: " 1595fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown + routeDescriptor); 1596c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } else { 1597c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown // 1. Reorder the route within the list. 1598fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown RouteInfo route = provider.mRoutes.get(sourceIndex); 1599fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown Collections.swap(provider.mRoutes, 1600c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown sourceIndex, targetIndex++); 1601c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown // 2. Update the route's contents. 1602c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown int changes = route.updateDescriptor(routeDescriptor); 1603fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown // 3. Unselect route if needed before notifying about changes. 1604fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown unselectRouteIfNeeded(route); 1605fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown // 4. Notify clients about changes. 1606c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if ((changes & RouteInfo.CHANGE_GENERAL) != 0) { 160711417b1cfde8f1749905f2d735623af9214148afJeff Brown if (DEBUG) { 160811417b1cfde8f1749905f2d735623af9214148afJeff Brown Log.d(TAG, "Route changed: " + route); 160911417b1cfde8f1749905f2d735623af9214148afJeff Brown } 1610c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown mCallbackHandler.post( 1611c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown CallbackHandler.MSG_ROUTE_CHANGED, route); 1612c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1613c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if ((changes & RouteInfo.CHANGE_VOLUME) != 0) { 161411417b1cfde8f1749905f2d735623af9214148afJeff Brown if (DEBUG) { 161511417b1cfde8f1749905f2d735623af9214148afJeff Brown Log.d(TAG, "Route volume changed: " + route); 161611417b1cfde8f1749905f2d735623af9214148afJeff Brown } 1617c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown mCallbackHandler.post( 1618c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown CallbackHandler.MSG_ROUTE_VOLUME_CHANGED, route); 1619c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1620c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if ((changes & RouteInfo.CHANGE_PRESENTATION_DISPLAY) != 0) { 162111417b1cfde8f1749905f2d735623af9214148afJeff Brown if (DEBUG) { 162211417b1cfde8f1749905f2d735623af9214148afJeff Brown Log.d(TAG, "Route presentation display changed: " 162311417b1cfde8f1749905f2d735623af9214148afJeff Brown + route); 162411417b1cfde8f1749905f2d735623af9214148afJeff Brown } 1625fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mCallbackHandler.post(CallbackHandler. 1626fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown MSG_ROUTE_PRESENTATION_DISPLAY_CHANGED, route); 1627c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1628c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1629c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1630fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } else { 1631fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown Log.w(TAG, "Ignoring invalid provider descriptor: " + providerDescriptor); 1632c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1633c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1634c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1635c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown // Dispose all remaining routes that do not have matching descriptors. 1636fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown for (int i = provider.mRoutes.size() - 1; i >= targetIndex; i--) { 1637fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown // 1. Delete the route's contents. 1638fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown RouteInfo route = provider.mRoutes.get(i); 1639c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown route.updateDescriptor(null); 1640fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown // 2. Remove the route from the list. 164111417b1cfde8f1749905f2d735623af9214148afJeff Brown mRoutes.remove(route); 1642fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown provider.mRoutes.remove(i); 1643fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown // 3. Unselect route if needed before notifying about removal. 1644fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown unselectRouteIfNeeded(route); 1645fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown // 4. Notify clients about removal. 164611417b1cfde8f1749905f2d735623af9214148afJeff Brown if (DEBUG) { 164711417b1cfde8f1749905f2d735623af9214148afJeff Brown Log.d(TAG, "Route removed: " + route); 164811417b1cfde8f1749905f2d735623af9214148afJeff Brown } 1649fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mCallbackHandler.post(CallbackHandler.MSG_ROUTE_REMOVED, route); 1650c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1651fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 165211417b1cfde8f1749905f2d735623af9214148afJeff Brown // Notify provider changed. 165311417b1cfde8f1749905f2d735623af9214148afJeff Brown if (DEBUG) { 165411417b1cfde8f1749905f2d735623af9214148afJeff Brown Log.d(TAG, "Provider changed: " + provider); 165511417b1cfde8f1749905f2d735623af9214148afJeff Brown } 165611417b1cfde8f1749905f2d735623af9214148afJeff Brown mCallbackHandler.post(CallbackHandler.MSG_PROVIDER_CHANGED, provider); 165711417b1cfde8f1749905f2d735623af9214148afJeff Brown 1658fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown // Choose a new selected route if needed. 1659fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown selectRouteIfNeeded(); 1660c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1661c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1662c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1663fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private void unselectRouteIfNeeded(RouteInfo route) { 1664fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (mDefaultRoute == route && !isRouteSelectable(route)) { 1665c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown Log.i(TAG, "Choosing a new default route because the current one " 1666fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown + "is no longer selectable: " + route); 1667c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown mDefaultRoute = null; 1668c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1669fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (mSelectedRoute == route && !isRouteSelectable(route)) { 1670fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown Log.i(TAG, "Choosing a new selected route because the current one " 1671fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown + "is no longer selectable: " + route); 1672fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown setSelectedRouteInternal(null); 1673fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 1674fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 1675fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 1676fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private void selectRouteIfNeeded() { 1677c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (mDefaultRoute == null && !mRoutes.isEmpty()) { 1678c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown for (RouteInfo route : mRoutes) { 1679c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (isSystemDefaultRoute(route) && isRouteSelectable(route)) { 1680c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown mDefaultRoute = route; 1681c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown break; 1682c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1683c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1684c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1685c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (mSelectedRoute == null) { 1686c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown setSelectedRouteInternal(mDefaultRoute); 1687c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1688c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1689c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1690c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown private boolean isRouteSelectable(RouteInfo route) { 1691c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown // This tests whether the route is still valid and enabled. 1692c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown // The route descriptor field is set to null when the route is removed. 1693c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return route.mDescriptor != null && route.mEnabled; 1694c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1695c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1696c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown private boolean isSystemDefaultRoute(RouteInfo route) { 1697fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return route.getProviderInstance() == mSystemProvider 1698c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown && route.mDescriptorId.equals( 1699c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown SystemMediaRouteProvider.DEFAULT_ROUTE_ID); 1700c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1701c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1702c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown private void setSelectedRouteInternal(RouteInfo route) { 1703c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (mSelectedRoute != route) { 1704c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (mSelectedRoute != null) { 170511417b1cfde8f1749905f2d735623af9214148afJeff Brown if (DEBUG) { 170611417b1cfde8f1749905f2d735623af9214148afJeff Brown Log.d(TAG, "Route unselected: " + mSelectedRoute); 170711417b1cfde8f1749905f2d735623af9214148afJeff Brown } 1708c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown mCallbackHandler.post(CallbackHandler.MSG_ROUTE_UNSELECTED, mSelectedRoute); 1709c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (mSelectedRouteController != null) { 1710129abf73ce9be1bc172b945263c7975ad1a3006fJeff Brown mSelectedRouteController.onUnselect(); 1711129abf73ce9be1bc172b945263c7975ad1a3006fJeff Brown mSelectedRouteController.onRelease(); 1712c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown mSelectedRouteController = null; 1713c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1714c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1715c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1716c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown mSelectedRoute = route; 1717c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1718c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (mSelectedRoute != null) { 1719fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mSelectedRouteController = route.getProviderInstance().onCreateRouteController( 1720c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown route.mDescriptorId); 1721c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (mSelectedRouteController != null) { 1722129abf73ce9be1bc172b945263c7975ad1a3006fJeff Brown mSelectedRouteController.onSelect(); 1723c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 172411417b1cfde8f1749905f2d735623af9214148afJeff Brown if (DEBUG) { 172511417b1cfde8f1749905f2d735623af9214148afJeff Brown Log.d(TAG, "Route selected: " + mSelectedRoute); 172611417b1cfde8f1749905f2d735623af9214148afJeff Brown } 1727c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown mCallbackHandler.post(CallbackHandler.MSG_ROUTE_SELECTED, mSelectedRoute); 1728c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1729c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1730c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1731c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1732c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown @Override 1733c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public RouteInfo getSystemRouteByDescriptorId(String id) { 1734fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown int providerIndex = findProviderInfo(mSystemProvider); 1735c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (providerIndex >= 0) { 1736fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown ProviderInfo provider = mProviders.get(providerIndex); 1737fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown int routeIndex = provider.findRouteByDescriptorId(id); 1738c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (routeIndex >= 0) { 1739fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return provider.mRoutes.get(routeIndex); 1740c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1741c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1742c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return null; 1743c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1744c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1745c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown private final class ProviderCallback extends MediaRouteProvider.Callback { 1746c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown @Override 1747c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public void onDescriptorChanged(MediaRouteProvider provider, 174811417b1cfde8f1749905f2d735623af9214148afJeff Brown MediaRouteProviderDescriptor descriptor) { 1749c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown updateProviderDescriptor(provider, descriptor); 1750c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1751c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1752c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1753c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown private final class CallbackHandler extends Handler { 1754c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown private final ArrayList<MediaRouter> mTempMediaRouters = 1755c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown new ArrayList<MediaRouter>(); 1756c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 175711417b1cfde8f1749905f2d735623af9214148afJeff Brown private static final int MSG_TYPE_MASK = 0xff00; 175811417b1cfde8f1749905f2d735623af9214148afJeff Brown private static final int MSG_TYPE_ROUTE = 0x0100; 175911417b1cfde8f1749905f2d735623af9214148afJeff Brown private static final int MSG_TYPE_PROVIDER = 0x0200; 176011417b1cfde8f1749905f2d735623af9214148afJeff Brown 176111417b1cfde8f1749905f2d735623af9214148afJeff Brown public static final int MSG_ROUTE_ADDED = MSG_TYPE_ROUTE | 1; 176211417b1cfde8f1749905f2d735623af9214148afJeff Brown public static final int MSG_ROUTE_REMOVED = MSG_TYPE_ROUTE | 2; 176311417b1cfde8f1749905f2d735623af9214148afJeff Brown public static final int MSG_ROUTE_CHANGED = MSG_TYPE_ROUTE | 3; 176411417b1cfde8f1749905f2d735623af9214148afJeff Brown public static final int MSG_ROUTE_VOLUME_CHANGED = MSG_TYPE_ROUTE | 4; 176511417b1cfde8f1749905f2d735623af9214148afJeff Brown public static final int MSG_ROUTE_PRESENTATION_DISPLAY_CHANGED = MSG_TYPE_ROUTE | 5; 176611417b1cfde8f1749905f2d735623af9214148afJeff Brown public static final int MSG_ROUTE_SELECTED = MSG_TYPE_ROUTE | 6; 176711417b1cfde8f1749905f2d735623af9214148afJeff Brown public static final int MSG_ROUTE_UNSELECTED = MSG_TYPE_ROUTE | 7; 176811417b1cfde8f1749905f2d735623af9214148afJeff Brown 176911417b1cfde8f1749905f2d735623af9214148afJeff Brown public static final int MSG_PROVIDER_ADDED = MSG_TYPE_PROVIDER | 1; 177011417b1cfde8f1749905f2d735623af9214148afJeff Brown public static final int MSG_PROVIDER_REMOVED = MSG_TYPE_PROVIDER | 2; 177111417b1cfde8f1749905f2d735623af9214148afJeff Brown public static final int MSG_PROVIDER_CHANGED = MSG_TYPE_PROVIDER | 3; 1772c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1773fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public void post(int msg, Object obj) { 1774fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown obtainMessage(msg, obj).sendToTarget(); 1775c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1776c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1777c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown @Override 1778c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public void handleMessage(Message msg) { 1779c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown final int what = msg.what; 1780fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown final Object obj = msg.obj; 1781c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1782c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown // Synchronize state with the system media router. 1783fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown syncWithSystemProvider(what, obj); 1784c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1785c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown // Invoke all registered callbacks. 1786c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown mTempMediaRouters.addAll(mRouters.values()); 1787c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown try { 1788c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown final int routerCount = mTempMediaRouters.size(); 1789c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown for (int i = 0; i < routerCount; i++) { 1790c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown final MediaRouter router = mTempMediaRouters.get(i); 179111417b1cfde8f1749905f2d735623af9214148afJeff Brown if (!router.mCallbackRecords.isEmpty()) { 179211417b1cfde8f1749905f2d735623af9214148afJeff Brown for (CallbackRecord record : router.mCallbackRecords) { 179311417b1cfde8f1749905f2d735623af9214148afJeff Brown invokeCallback(router, record, what, obj); 1794c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1795c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1796c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1797c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } finally { 1798c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown mTempMediaRouters.clear(); 1799c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1800c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1801c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 1802fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private void syncWithSystemProvider(int what, Object obj) { 1803c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown switch (what) { 1804c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown case MSG_ROUTE_ADDED: 1805fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mSystemProvider.onSyncRouteAdded((RouteInfo)obj); 1806c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown break; 1807c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown case MSG_ROUTE_REMOVED: 1808fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mSystemProvider.onSyncRouteRemoved((RouteInfo)obj); 1809c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown break; 1810c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown case MSG_ROUTE_CHANGED: 1811fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mSystemProvider.onSyncRouteChanged((RouteInfo)obj); 1812c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown break; 1813c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown case MSG_ROUTE_SELECTED: 1814fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mSystemProvider.onSyncRouteSelected((RouteInfo)obj); 1815c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown break; 1816c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1817c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1818c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 181911417b1cfde8f1749905f2d735623af9214148afJeff Brown private void invokeCallback(MediaRouter router, CallbackRecord record, 1820fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown int what, Object obj) { 182111417b1cfde8f1749905f2d735623af9214148afJeff Brown final MediaRouter.Callback callback = record.mCallback; 182211417b1cfde8f1749905f2d735623af9214148afJeff Brown switch (what & MSG_TYPE_MASK) { 182311417b1cfde8f1749905f2d735623af9214148afJeff Brown case MSG_TYPE_ROUTE: { 182411417b1cfde8f1749905f2d735623af9214148afJeff Brown final RouteInfo route = (RouteInfo)obj; 182511417b1cfde8f1749905f2d735623af9214148afJeff Brown if (!record.filterRouteEvent(route)) { 182611417b1cfde8f1749905f2d735623af9214148afJeff Brown break; 182711417b1cfde8f1749905f2d735623af9214148afJeff Brown } 182811417b1cfde8f1749905f2d735623af9214148afJeff Brown switch (what) { 182911417b1cfde8f1749905f2d735623af9214148afJeff Brown case MSG_ROUTE_ADDED: 183011417b1cfde8f1749905f2d735623af9214148afJeff Brown callback.onRouteAdded(router, route); 183111417b1cfde8f1749905f2d735623af9214148afJeff Brown break; 183211417b1cfde8f1749905f2d735623af9214148afJeff Brown case MSG_ROUTE_REMOVED: 183311417b1cfde8f1749905f2d735623af9214148afJeff Brown callback.onRouteRemoved(router, route); 183411417b1cfde8f1749905f2d735623af9214148afJeff Brown break; 183511417b1cfde8f1749905f2d735623af9214148afJeff Brown case MSG_ROUTE_CHANGED: 183611417b1cfde8f1749905f2d735623af9214148afJeff Brown callback.onRouteChanged(router, route); 183711417b1cfde8f1749905f2d735623af9214148afJeff Brown break; 183811417b1cfde8f1749905f2d735623af9214148afJeff Brown case MSG_ROUTE_VOLUME_CHANGED: 183911417b1cfde8f1749905f2d735623af9214148afJeff Brown callback.onRouteVolumeChanged(router, route); 184011417b1cfde8f1749905f2d735623af9214148afJeff Brown break; 184111417b1cfde8f1749905f2d735623af9214148afJeff Brown case MSG_ROUTE_PRESENTATION_DISPLAY_CHANGED: 184211417b1cfde8f1749905f2d735623af9214148afJeff Brown callback.onRoutePresentationDisplayChanged(router, route); 184311417b1cfde8f1749905f2d735623af9214148afJeff Brown break; 184411417b1cfde8f1749905f2d735623af9214148afJeff Brown case MSG_ROUTE_SELECTED: 184511417b1cfde8f1749905f2d735623af9214148afJeff Brown callback.onRouteSelected(router, route); 184611417b1cfde8f1749905f2d735623af9214148afJeff Brown break; 184711417b1cfde8f1749905f2d735623af9214148afJeff Brown case MSG_ROUTE_UNSELECTED: 184811417b1cfde8f1749905f2d735623af9214148afJeff Brown callback.onRouteUnselected(router, route); 184911417b1cfde8f1749905f2d735623af9214148afJeff Brown break; 185011417b1cfde8f1749905f2d735623af9214148afJeff Brown } 1851c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown break; 185211417b1cfde8f1749905f2d735623af9214148afJeff Brown } 185311417b1cfde8f1749905f2d735623af9214148afJeff Brown case MSG_TYPE_PROVIDER: { 185411417b1cfde8f1749905f2d735623af9214148afJeff Brown final ProviderInfo provider = (ProviderInfo)obj; 185511417b1cfde8f1749905f2d735623af9214148afJeff Brown switch (what) { 185611417b1cfde8f1749905f2d735623af9214148afJeff Brown case MSG_PROVIDER_ADDED: 185711417b1cfde8f1749905f2d735623af9214148afJeff Brown callback.onProviderAdded(router, provider); 185811417b1cfde8f1749905f2d735623af9214148afJeff Brown break; 185911417b1cfde8f1749905f2d735623af9214148afJeff Brown case MSG_PROVIDER_REMOVED: 186011417b1cfde8f1749905f2d735623af9214148afJeff Brown callback.onProviderRemoved(router, provider); 186111417b1cfde8f1749905f2d735623af9214148afJeff Brown break; 186211417b1cfde8f1749905f2d735623af9214148afJeff Brown case MSG_PROVIDER_CHANGED: 186311417b1cfde8f1749905f2d735623af9214148afJeff Brown callback.onProviderChanged(router, provider); 186411417b1cfde8f1749905f2d735623af9214148afJeff Brown break; 186511417b1cfde8f1749905f2d735623af9214148afJeff Brown } 186611417b1cfde8f1749905f2d735623af9214148afJeff Brown } 1867c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1868c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1869c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1870c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 1871c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown} 1872