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 19adf0f4a217e14894af07dfa9f46cad7d98b8a7f4Jeff Brownimport android.content.ComponentName; 20c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brownimport android.content.Context; 21c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brownimport android.content.Intent; 22c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brownimport android.os.Handler; 23c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brownimport android.os.Message; 24429c3b17b88ebd8c4512e9179fd9d48333c0979eTor Norbyeimport android.support.annotation.NonNull; 25429c3b17b88ebd8c4512e9179fd9d48333c0979eTor Norbyeimport android.support.annotation.Nullable; 26b507e525a61ed761eecfc2eaaf19af7e8db5dca5Jeff Brownimport android.support.v7.media.MediaRouter.ControlRequestCallback; 27c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 28c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown/** 29c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Media route providers are used to publish additional media routes for 30c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * use within an application. Media route providers may also be declared 31c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * as a service to publish additional media routes to all applications 32c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * in the system. 33c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * <p> 3411417b1cfde8f1749905f2d735623af9214148afJeff Brown * The purpose of a media route provider is to discover media routes that satisfy 3511417b1cfde8f1749905f2d735623af9214148afJeff Brown * the criteria specified by the current {@link MediaRouteDiscoveryRequest} and publish a 3611417b1cfde8f1749905f2d735623af9214148afJeff Brown * {@link MediaRouteProviderDescriptor} with information about each route by calling 3711417b1cfde8f1749905f2d735623af9214148afJeff Brown * {@link #setDescriptor} to notify the currently registered {@link Callback}. 3811417b1cfde8f1749905f2d735623af9214148afJeff Brown * </p><p> 3911417b1cfde8f1749905f2d735623af9214148afJeff Brown * The provider should watch for changes to the discovery request by implementing 4011417b1cfde8f1749905f2d735623af9214148afJeff Brown * {@link #onDiscoveryRequestChanged} and updating the set of routes that it is 4111417b1cfde8f1749905f2d735623af9214148afJeff Brown * attempting to discover. It should also handle route control requests such 4211417b1cfde8f1749905f2d735623af9214148afJeff Brown * as volume changes or {@link MediaControlIntent media control intents} 4311417b1cfde8f1749905f2d735623af9214148afJeff Brown * by implementing {@link #onCreateRouteController} to return a {@link RouteController} 4411417b1cfde8f1749905f2d735623af9214148afJeff Brown * for a particular route. 4511417b1cfde8f1749905f2d735623af9214148afJeff Brown * </p><p> 4611417b1cfde8f1749905f2d735623af9214148afJeff Brown * A media route provider may be used privately within the scope of a single 4711417b1cfde8f1749905f2d735623af9214148afJeff Brown * application process by calling {@link MediaRouter#addProvider MediaRouter.addProvider} 4811417b1cfde8f1749905f2d735623af9214148afJeff Brown * to add it to the local {@link MediaRouter}. A media route provider may also be made 4911417b1cfde8f1749905f2d735623af9214148afJeff Brown * available globally to all applications by registering a {@link MediaRouteProviderService} 5011417b1cfde8f1749905f2d735623af9214148afJeff Brown * in the provider's manifest. When the media route provider is registered 5111417b1cfde8f1749905f2d735623af9214148afJeff Brown * as a service, all applications that use the media router API will be able to 5211417b1cfde8f1749905f2d735623af9214148afJeff Brown * discover and used the provider's routes without having to install anything else. 53c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * </p><p> 54c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * This object must only be accessed on the main thread. 55c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * </p> 56c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 57c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brownpublic abstract class MediaRouteProvider { 58c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown private static final int MSG_DELIVER_DESCRIPTOR_CHANGED = 1; 5911417b1cfde8f1749905f2d735623af9214148afJeff Brown private static final int MSG_DELIVER_DISCOVERY_REQUEST_CHANGED = 2; 60c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 61c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown private final Context mContext; 62fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private final ProviderMetadata mMetadata; 63c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown private final ProviderHandler mHandler = new ProviderHandler(); 64c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 6511417b1cfde8f1749905f2d735623af9214148afJeff Brown private Callback mCallback; 6611417b1cfde8f1749905f2d735623af9214148afJeff Brown 6711417b1cfde8f1749905f2d735623af9214148afJeff Brown private MediaRouteDiscoveryRequest mDiscoveryRequest; 6811417b1cfde8f1749905f2d735623af9214148afJeff Brown private boolean mPendingDiscoveryRequestChange; 6911417b1cfde8f1749905f2d735623af9214148afJeff Brown 7011417b1cfde8f1749905f2d735623af9214148afJeff Brown private MediaRouteProviderDescriptor mDescriptor; 71c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown private boolean mPendingDescriptorChange; 72c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 73c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 74c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Creates a media route provider. 75c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 76c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @param context The context. 77c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 78429c3b17b88ebd8c4512e9179fd9d48333c0979eTor Norbye public MediaRouteProvider(@NonNull Context context) { 79fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown this(context, null); 80fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 81fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 82fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown MediaRouteProvider(Context context, ProviderMetadata metadata) { 83c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (context == null) { 84c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown throw new IllegalArgumentException("context must not be null"); 85c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 86c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 87c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown mContext = context; 88fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (metadata == null) { 89adf0f4a217e14894af07dfa9f46cad7d98b8a7f4Jeff Brown mMetadata = new ProviderMetadata(new ComponentName(context, getClass())); 90fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } else { 91fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mMetadata = metadata; 92fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 93c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 94c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 95c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 96c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Gets the context of the media route provider. 97c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 98c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public final Context getContext() { 99c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return mContext; 100c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 101c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 10211417b1cfde8f1749905f2d735623af9214148afJeff Brown /** 10311417b1cfde8f1749905f2d735623af9214148afJeff Brown * Gets the provider's handler which is associated with the main thread. 10411417b1cfde8f1749905f2d735623af9214148afJeff Brown */ 10511417b1cfde8f1749905f2d735623af9214148afJeff Brown public final Handler getHandler() { 10611417b1cfde8f1749905f2d735623af9214148afJeff Brown return mHandler; 10711417b1cfde8f1749905f2d735623af9214148afJeff Brown } 10811417b1cfde8f1749905f2d735623af9214148afJeff Brown 10911417b1cfde8f1749905f2d735623af9214148afJeff Brown /** 11011417b1cfde8f1749905f2d735623af9214148afJeff Brown * Gets some metadata about the provider's implementation. 11111417b1cfde8f1749905f2d735623af9214148afJeff Brown */ 11211417b1cfde8f1749905f2d735623af9214148afJeff Brown public final ProviderMetadata getMetadata() { 113fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return mMetadata; 114fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 115fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 116c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 11711417b1cfde8f1749905f2d735623af9214148afJeff Brown * Sets a callback to invoke when the provider's descriptor changes. 11811417b1cfde8f1749905f2d735623af9214148afJeff Brown * 11911417b1cfde8f1749905f2d735623af9214148afJeff Brown * @param callback The callback to use, or null if none. 12011417b1cfde8f1749905f2d735623af9214148afJeff Brown */ 121429c3b17b88ebd8c4512e9179fd9d48333c0979eTor Norbye public final void setCallback(@Nullable Callback callback) { 12211417b1cfde8f1749905f2d735623af9214148afJeff Brown MediaRouter.checkCallingThread(); 12311417b1cfde8f1749905f2d735623af9214148afJeff Brown mCallback = callback; 12411417b1cfde8f1749905f2d735623af9214148afJeff Brown } 12511417b1cfde8f1749905f2d735623af9214148afJeff Brown 12611417b1cfde8f1749905f2d735623af9214148afJeff Brown /** 12711417b1cfde8f1749905f2d735623af9214148afJeff Brown * Gets the current discovery request which informs the provider about the 12811417b1cfde8f1749905f2d735623af9214148afJeff Brown * kinds of routes to discover and whether to perform active scanning. 12911417b1cfde8f1749905f2d735623af9214148afJeff Brown * 13011417b1cfde8f1749905f2d735623af9214148afJeff Brown * @return The current discovery request, or null if no discovery is needed at this time. 13111417b1cfde8f1749905f2d735623af9214148afJeff Brown * 13211417b1cfde8f1749905f2d735623af9214148afJeff Brown * @see #onDiscoveryRequestChanged 13311417b1cfde8f1749905f2d735623af9214148afJeff Brown */ 134429c3b17b88ebd8c4512e9179fd9d48333c0979eTor Norbye @Nullable 13511417b1cfde8f1749905f2d735623af9214148afJeff Brown public final MediaRouteDiscoveryRequest getDiscoveryRequest() { 13611417b1cfde8f1749905f2d735623af9214148afJeff Brown return mDiscoveryRequest; 13711417b1cfde8f1749905f2d735623af9214148afJeff Brown } 13811417b1cfde8f1749905f2d735623af9214148afJeff Brown 13911417b1cfde8f1749905f2d735623af9214148afJeff Brown /** 14011417b1cfde8f1749905f2d735623af9214148afJeff Brown * Sets a discovery request to inform the provider about the kinds of 14111417b1cfde8f1749905f2d735623af9214148afJeff Brown * routes that its clients would like to discover and whether to perform active scanning. 14211417b1cfde8f1749905f2d735623af9214148afJeff Brown * 14311417b1cfde8f1749905f2d735623af9214148afJeff Brown * @param request The discovery request, or null if no discovery is needed at this time. 14411417b1cfde8f1749905f2d735623af9214148afJeff Brown * 14511417b1cfde8f1749905f2d735623af9214148afJeff Brown * @see #onDiscoveryRequestChanged 14611417b1cfde8f1749905f2d735623af9214148afJeff Brown */ 14711417b1cfde8f1749905f2d735623af9214148afJeff Brown public final void setDiscoveryRequest(MediaRouteDiscoveryRequest request) { 14811417b1cfde8f1749905f2d735623af9214148afJeff Brown MediaRouter.checkCallingThread(); 14911417b1cfde8f1749905f2d735623af9214148afJeff Brown 15011417b1cfde8f1749905f2d735623af9214148afJeff Brown if (mDiscoveryRequest == request 15111417b1cfde8f1749905f2d735623af9214148afJeff Brown || (mDiscoveryRequest != null && mDiscoveryRequest.equals(request))) { 15211417b1cfde8f1749905f2d735623af9214148afJeff Brown return; 15311417b1cfde8f1749905f2d735623af9214148afJeff Brown } 15411417b1cfde8f1749905f2d735623af9214148afJeff Brown 15511417b1cfde8f1749905f2d735623af9214148afJeff Brown mDiscoveryRequest = request; 15611417b1cfde8f1749905f2d735623af9214148afJeff Brown if (!mPendingDiscoveryRequestChange) { 15711417b1cfde8f1749905f2d735623af9214148afJeff Brown mPendingDiscoveryRequestChange = true; 15811417b1cfde8f1749905f2d735623af9214148afJeff Brown mHandler.sendEmptyMessage(MSG_DELIVER_DISCOVERY_REQUEST_CHANGED); 15911417b1cfde8f1749905f2d735623af9214148afJeff Brown } 16011417b1cfde8f1749905f2d735623af9214148afJeff Brown } 16111417b1cfde8f1749905f2d735623af9214148afJeff Brown 16211417b1cfde8f1749905f2d735623af9214148afJeff Brown private void deliverDiscoveryRequestChanged() { 16311417b1cfde8f1749905f2d735623af9214148afJeff Brown mPendingDiscoveryRequestChange = false; 16411417b1cfde8f1749905f2d735623af9214148afJeff Brown onDiscoveryRequestChanged(mDiscoveryRequest); 16511417b1cfde8f1749905f2d735623af9214148afJeff Brown } 16611417b1cfde8f1749905f2d735623af9214148afJeff Brown 16711417b1cfde8f1749905f2d735623af9214148afJeff Brown /** 16811417b1cfde8f1749905f2d735623af9214148afJeff Brown * Called by the media router when the {@link MediaRouteDiscoveryRequest discovery request} 16911417b1cfde8f1749905f2d735623af9214148afJeff Brown * has changed. 17011417b1cfde8f1749905f2d735623af9214148afJeff Brown * <p> 17111417b1cfde8f1749905f2d735623af9214148afJeff Brown * Whenever an applications calls {@link MediaRouter#addCallback} to register 17211417b1cfde8f1749905f2d735623af9214148afJeff Brown * a callback, it also provides a selector to specify the kinds of routes that 17311417b1cfde8f1749905f2d735623af9214148afJeff Brown * it is interested in. The media router combines all of these selectors together 17411417b1cfde8f1749905f2d735623af9214148afJeff Brown * to generate a {@link MediaRouteDiscoveryRequest} and notifies each provider when a change 17511417b1cfde8f1749905f2d735623af9214148afJeff Brown * occurs by calling {@link #setDiscoveryRequest} which posts a message to invoke 17611417b1cfde8f1749905f2d735623af9214148afJeff Brown * this method asynchronously. 17711417b1cfde8f1749905f2d735623af9214148afJeff Brown * </p><p> 17811417b1cfde8f1749905f2d735623af9214148afJeff Brown * The provider should examine the {@link MediaControlIntent media control categories} 17911417b1cfde8f1749905f2d735623af9214148afJeff Brown * in the discovery request's {@link MediaRouteSelector selector} to determine what 18011417b1cfde8f1749905f2d735623af9214148afJeff Brown * kinds of routes it should try to discover and whether it should perform active 18111417b1cfde8f1749905f2d735623af9214148afJeff Brown * or passive scans. In many cases, the provider may be able to save power by 18211417b1cfde8f1749905f2d735623af9214148afJeff Brown * determining that the selector does not contain any categories that it supports 18311417b1cfde8f1749905f2d735623af9214148afJeff Brown * and it can therefore avoid performing any scans at all. 18411417b1cfde8f1749905f2d735623af9214148afJeff Brown * </p> 18511417b1cfde8f1749905f2d735623af9214148afJeff Brown * 18611417b1cfde8f1749905f2d735623af9214148afJeff Brown * @param request The new discovery request, or null if no discovery is needed at this time. 18711417b1cfde8f1749905f2d735623af9214148afJeff Brown * 18811417b1cfde8f1749905f2d735623af9214148afJeff Brown * @see MediaRouter#addCallback 18911417b1cfde8f1749905f2d735623af9214148afJeff Brown */ 190429c3b17b88ebd8c4512e9179fd9d48333c0979eTor Norbye public void onDiscoveryRequestChanged(@Nullable MediaRouteDiscoveryRequest request) { 19111417b1cfde8f1749905f2d735623af9214148afJeff Brown } 19211417b1cfde8f1749905f2d735623af9214148afJeff Brown 19311417b1cfde8f1749905f2d735623af9214148afJeff Brown /** 194fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * Gets the provider's descriptor. 195fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * <p> 196fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * The descriptor describes the state of the media route provider and 197fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * the routes that it publishes. Watch for changes to the descriptor 19811417b1cfde8f1749905f2d735623af9214148afJeff Brown * by registering a {@link Callback callback} with {@link #setCallback}. 199fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * </p> 200c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 20111417b1cfde8f1749905f2d735623af9214148afJeff Brown * @return The media route provider descriptor, or null if none. 20211417b1cfde8f1749905f2d735623af9214148afJeff Brown * 20311417b1cfde8f1749905f2d735623af9214148afJeff Brown * @see Callback#onDescriptorChanged 204c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 205429c3b17b88ebd8c4512e9179fd9d48333c0979eTor Norbye @Nullable 20611417b1cfde8f1749905f2d735623af9214148afJeff Brown public final MediaRouteProviderDescriptor getDescriptor() { 207c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return mDescriptor; 208c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 209c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 210c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 211c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Sets the provider's descriptor. 212c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * <p> 21311417b1cfde8f1749905f2d735623af9214148afJeff Brown * The provider must call this method to notify the currently registered 21411417b1cfde8f1749905f2d735623af9214148afJeff Brown * {@link Callback callback} about the change to the provider's descriptor. 215c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * </p> 216c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 217fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * @param descriptor The updated route provider descriptor, or null if none. 21811417b1cfde8f1749905f2d735623af9214148afJeff Brown * 21911417b1cfde8f1749905f2d735623af9214148afJeff Brown * @see Callback#onDescriptorChanged 220c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 221429c3b17b88ebd8c4512e9179fd9d48333c0979eTor Norbye public final void setDescriptor(@Nullable MediaRouteProviderDescriptor descriptor) { 222c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown MediaRouter.checkCallingThread(); 223c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 224c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (mDescriptor != descriptor) { 225c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown mDescriptor = descriptor; 226c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown if (!mPendingDescriptorChange) { 227c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown mPendingDescriptorChange = true; 228c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown mHandler.sendEmptyMessage(MSG_DELIVER_DESCRIPTOR_CHANGED); 229c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 230c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 231c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 232c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 233c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown private void deliverDescriptorChanged() { 234c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown mPendingDescriptorChange = false; 235c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 23611417b1cfde8f1749905f2d735623af9214148afJeff Brown if (mCallback != null) { 23711417b1cfde8f1749905f2d735623af9214148afJeff Brown mCallback.onDescriptorChanged(this, mDescriptor); 238c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 239c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 240c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 241c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 242c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Called by the media router to obtain a route controller for a particular route. 243c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * <p> 2443b11cd2027d3249ec1d56939d3d3236cbd7ec91aJeff Brown * The media router will invoke the {@link RouteController#onRelease} method of the route 245fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * controller when it is no longer needed to allow it to free its resources. 246c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * </p> 247c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 248c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @param routeId The unique id of the route. 249c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @return The route controller. Returns null if there is no such route or if the route 250c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * cannot be controlled using the route controller interface. 251c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 252429c3b17b88ebd8c4512e9179fd9d48333c0979eTor Norbye @Nullable 253c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public RouteController onCreateRouteController(String routeId) { 254c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return null; 255c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 256c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 257c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 25811417b1cfde8f1749905f2d735623af9214148afJeff Brown * Describes properties of the route provider's implementation. 25928520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown * <p> 26011417b1cfde8f1749905f2d735623af9214148afJeff Brown * This object is immutable once created. 26128520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown * </p> 26228520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown */ 26311417b1cfde8f1749905f2d735623af9214148afJeff Brown public static final class ProviderMetadata { 264adf0f4a217e14894af07dfa9f46cad7d98b8a7f4Jeff Brown private final ComponentName mComponentName; 265fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 266adf0f4a217e14894af07dfa9f46cad7d98b8a7f4Jeff Brown ProviderMetadata(ComponentName componentName) { 267adf0f4a217e14894af07dfa9f46cad7d98b8a7f4Jeff Brown if (componentName == null) { 268adf0f4a217e14894af07dfa9f46cad7d98b8a7f4Jeff Brown throw new IllegalArgumentException("componentName must not be null"); 269fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 270adf0f4a217e14894af07dfa9f46cad7d98b8a7f4Jeff Brown mComponentName = componentName; 271fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 272fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 273c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 274adf0f4a217e14894af07dfa9f46cad7d98b8a7f4Jeff Brown * Gets the provider's package name. 275c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 27611417b1cfde8f1749905f2d735623af9214148afJeff Brown public String getPackageName() { 277adf0f4a217e14894af07dfa9f46cad7d98b8a7f4Jeff Brown return mComponentName.getPackageName(); 278adf0f4a217e14894af07dfa9f46cad7d98b8a7f4Jeff Brown } 279adf0f4a217e14894af07dfa9f46cad7d98b8a7f4Jeff Brown 280adf0f4a217e14894af07dfa9f46cad7d98b8a7f4Jeff Brown /** 281adf0f4a217e14894af07dfa9f46cad7d98b8a7f4Jeff Brown * Gets the provider's component name. 282adf0f4a217e14894af07dfa9f46cad7d98b8a7f4Jeff Brown */ 283adf0f4a217e14894af07dfa9f46cad7d98b8a7f4Jeff Brown public ComponentName getComponentName() { 284adf0f4a217e14894af07dfa9f46cad7d98b8a7f4Jeff Brown return mComponentName; 285c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 286c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 287c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown @Override 288c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public String toString() { 289adf0f4a217e14894af07dfa9f46cad7d98b8a7f4Jeff Brown return "ProviderMetadata{ componentName=" 290adf0f4a217e14894af07dfa9f46cad7d98b8a7f4Jeff Brown + mComponentName.flattenToShortString() + " }"; 291c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 292c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 293c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 294c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 295c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Provides control over a particular route. 296c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * <p> 297c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * The media router obtains a route controller for a route whenever it needs 298c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * to control a route. When a route is selected, the media router invokes 2993b11cd2027d3249ec1d56939d3d3236cbd7ec91aJeff Brown * the {@link #onSelect} method of its route controller. While selected, 300c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * the media router may call other methods of the route controller to 301c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * request that it perform certain actions to the route. When a route is 3023b11cd2027d3249ec1d56939d3d3236cbd7ec91aJeff Brown * unselected, the media router invokes the {@link #onUnselect} method of its 303c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * route controller. When the media route no longer needs the route controller 3043b11cd2027d3249ec1d56939d3d3236cbd7ec91aJeff Brown * it will invoke the {@link #onRelease} method to allow the route controller 305c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * to free its resources. 306c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * </p><p> 307fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * There may be multiple route controllers simultaneously active for the 308fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * same route. Each route controller will be released separately. 309fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * </p><p> 310c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * All operations on the route controller are asynchronous and 311c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * results are communicated via callbacks. 312c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * </p> 313c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 314c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public static abstract class RouteController { 315c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 316c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Releases the route controller, allowing it to free its resources. 317c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 318129abf73ce9be1bc172b945263c7975ad1a3006fJeff Brown public void onRelease() { 319c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 320c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 321c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 322c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Selects the route. 323c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 324129abf73ce9be1bc172b945263c7975ad1a3006fJeff Brown public void onSelect() { 325c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 326c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 327c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 328c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Unselects the route. 329c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 330129abf73ce9be1bc172b945263c7975ad1a3006fJeff Brown public void onUnselect() { 331c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 332c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 333c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 33494be6100218126ce6a08bf1f56209578500b361fRoboErik * Unselects the route and provides a reason. The default implementation 33594be6100218126ce6a08bf1f56209578500b361fRoboErik * calls {@link #onUnselect()}. 33694be6100218126ce6a08bf1f56209578500b361fRoboErik * <p> 33794be6100218126ce6a08bf1f56209578500b361fRoboErik * The reason provided will be one of the following: 33894be6100218126ce6a08bf1f56209578500b361fRoboErik * <ul> 33994be6100218126ce6a08bf1f56209578500b361fRoboErik * <li>{@link MediaRouter#UNSELECT_REASON_UNKNOWN}</li> 34094be6100218126ce6a08bf1f56209578500b361fRoboErik * <li>{@link MediaRouter#UNSELECT_REASON_DISCONNECTED}</li> 34194be6100218126ce6a08bf1f56209578500b361fRoboErik * <li>{@link MediaRouter#UNSELECT_REASON_STOPPED}</li> 34294be6100218126ce6a08bf1f56209578500b361fRoboErik * <li>{@link MediaRouter#UNSELECT_REASON_ROUTE_CHANGED}</li> 34394be6100218126ce6a08bf1f56209578500b361fRoboErik * </ul> 34494be6100218126ce6a08bf1f56209578500b361fRoboErik * 34594be6100218126ce6a08bf1f56209578500b361fRoboErik * @param reason The reason for unselecting the route. 34694be6100218126ce6a08bf1f56209578500b361fRoboErik */ 34794be6100218126ce6a08bf1f56209578500b361fRoboErik public void onUnselect(int reason) { 34894be6100218126ce6a08bf1f56209578500b361fRoboErik onUnselect(); 34994be6100218126ce6a08bf1f56209578500b361fRoboErik } 35094be6100218126ce6a08bf1f56209578500b361fRoboErik 35194be6100218126ce6a08bf1f56209578500b361fRoboErik /** 352c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Requests to set the volume of the route. 353c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 35411417b1cfde8f1749905f2d735623af9214148afJeff Brown * @param volume The new volume value between 0 and {@link MediaRouteDescriptor#getVolumeMax}. 355c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 356129abf73ce9be1bc172b945263c7975ad1a3006fJeff Brown public void onSetVolume(int volume) { 357c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 358c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 359c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 360c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Requests an incremental volume update for the route. 361c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 362c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @param delta The delta to add to the current volume. 363c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 364129abf73ce9be1bc172b945263c7975ad1a3006fJeff Brown public void onUpdateVolume(int delta) { 365c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 366c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 367c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 368129abf73ce9be1bc172b945263c7975ad1a3006fJeff Brown * Performs a {@link MediaControlIntent media control} request 369129abf73ce9be1bc172b945263c7975ad1a3006fJeff Brown * asynchronously on behalf of the route. 370c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 371c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @param intent A {@link MediaControlIntent media control intent}. 372c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @param callback A {@link ControlRequestCallback} to invoke with the result 373c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * of the request, or null if no result is required. 374fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * @return True if the controller intends to handle the request and will 37511417b1cfde8f1749905f2d735623af9214148afJeff Brown * invoke the callback when finished. False if the controller will not 376fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * handle the request and will not invoke the callback. 377c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 378c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * @see MediaControlIntent 379c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 380429c3b17b88ebd8c4512e9179fd9d48333c0979eTor Norbye public boolean onControlRequest(Intent intent, @Nullable ControlRequestCallback callback) { 381c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown return false; 382c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 383c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 384c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 385c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 386c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Callback which is invoked when route information becomes available or changes. 387c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 388c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public static abstract class Callback { 389c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown /** 390c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * Called when information about a route provider and its routes changes. 391c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown * 39211417b1cfde8f1749905f2d735623af9214148afJeff Brown * @param provider The media route provider that changed, never null. 39311417b1cfde8f1749905f2d735623af9214148afJeff Brown * @param descriptor The new media route provider descriptor, or null if none. 394c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown */ 395429c3b17b88ebd8c4512e9179fd9d48333c0979eTor Norbye public void onDescriptorChanged(@NonNull MediaRouteProvider provider, 396429c3b17b88ebd8c4512e9179fd9d48333c0979eTor Norbye @Nullable MediaRouteProviderDescriptor descriptor) { 397c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 398c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 399c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown 400c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown private final class ProviderHandler extends Handler { 401c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown @Override 402c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown public void handleMessage(Message msg) { 403c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown switch (msg.what) { 404c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown case MSG_DELIVER_DESCRIPTOR_CHANGED: 405c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown deliverDescriptorChanged(); 406c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown break; 40711417b1cfde8f1749905f2d735623af9214148afJeff Brown case MSG_DELIVER_DISCOVERY_REQUEST_CHANGED: 40811417b1cfde8f1749905f2d735623af9214148afJeff Brown deliverDiscoveryRequestChanged(); 40911417b1cfde8f1749905f2d735623af9214148afJeff Brown break; 410c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 411c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 412c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown } 413c21f57ed68b81a77167f1df000b0e272e1598bc0Jeff Brown} 414