[go: nahoru, domu]

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