1fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown/*
2fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * Copyright (C) 2013 The Android Open Source Project
3fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown *
4fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * Licensed under the Apache License, Version 2.0 (the "License");
5fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * you may not use this file except in compliance with the License.
6fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * You may obtain a copy of the License at
7fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown *
8fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown *      http://www.apache.org/licenses/LICENSE-2.0
9fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown *
10fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * Unless required by applicable law or agreed to in writing, software
11fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * distributed under the License is distributed on an "AS IS" BASIS,
12fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * See the License for the specific language governing permissions and
14fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * limitations under the License.
15fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown */
16fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
17b507e525a61ed761eecfc2eaaf19af7e8db5dca5Jeff Brownpackage android.support.v7.media;
18fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
19fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brownimport android.app.Service;
20fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brownimport android.content.Intent;
219c83739aefcb1748551645a656bece0d864cef76Sungsoo Limimport android.os.Bundle;
229c83739aefcb1748551645a656bece0d864cef76Sungsoo Limimport android.os.DeadObjectException;
23fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brownimport android.os.Handler;
24fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brownimport android.os.IBinder;
25fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brownimport android.os.IBinder.DeathRecipient;
26fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brownimport android.os.Message;
27fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brownimport android.os.Messenger;
28fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brownimport android.os.RemoteException;
29fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brownimport android.util.Log;
30fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brownimport android.util.SparseArray;
31fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
32fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brownimport java.lang.ref.WeakReference;
33fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brownimport java.util.ArrayList;
349c83739aefcb1748551645a656bece0d864cef76Sungsoo Limimport java.util.List;
35fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
363efa63d3b896244713e84acbb5945562dce41d77Jeff Brownimport static android.support.v7.media.MediaRouteProviderProtocol.*;
373efa63d3b896244713e84acbb5945562dce41d77Jeff Brown
38fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown/**
39fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * Base class for media route provider services.
40fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * <p>
41d8e02077fc00aabc7432246e2301626fb342129dSungsoo Lim * A media router will bind to media route provider services when a callback is added via
42d8e02077fc00aabc7432246e2301626fb342129dSungsoo Lim * {@link MediaRouter#addCallback(MediaRouteSelector, MediaRouter.Callback, int)} with a discovery
43d8e02077fc00aabc7432246e2301626fb342129dSungsoo Lim * flag: {@link MediaRouter#CALLBACK_FLAG_REQUEST_DISCOVERY},
44d8e02077fc00aabc7432246e2301626fb342129dSungsoo Lim * {@link MediaRouter#CALLBACK_FLAG_FORCE_DISCOVERY}, or
45d8e02077fc00aabc7432246e2301626fb342129dSungsoo Lim * {@link MediaRouter#CALLBACK_FLAG_PERFORM_ACTIVE_SCAN}, and will unbind when the callback
46d8e02077fc00aabc7432246e2301626fb342129dSungsoo Lim * is removed via {@link MediaRouter#removeCallback(MediaRouter.Callback)}.
47d8e02077fc00aabc7432246e2301626fb342129dSungsoo Lim * </p><p>
48fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * To implement your own media route provider service, extend this class and
49fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * override the {@link #onCreateMediaRouteProvider} method to return an
50fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * instance of your {@link MediaRouteProvider}.
51fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * </p><p>
52fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * Declare your media route provider service in your application manifest
53fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * like this:
54fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * </p>
55fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * <pre>
56fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown *   &lt;service android:name=".MyMediaRouteProviderService"
57fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown *           android:label="@string/my_media_route_provider_service">
58fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown *       &lt;intent-filter>
59fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown *           &lt;action android:name="android.media.MediaRouteProviderService" />
60fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown *       &lt;/intent-filter>
61fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown *   &lt;/service>
62fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * </pre>
63fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown */
64fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brownpublic abstract class MediaRouteProviderService extends Service {
65e2c6a94b6e4aab502f9b88dd3ff664bd90b25839Aurimas Liutikas    static final String TAG = "MediaRouteProviderSrv"; // max. 23 chars
66e2c6a94b6e4aab502f9b88dd3ff664bd90b25839Aurimas Liutikas    static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
67fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
68fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    private final ArrayList<ClientRecord> mClients = new ArrayList<ClientRecord>();
69fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    private final ReceiveHandler mReceiveHandler;
70fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    private final Messenger mReceiveMessenger;
71e2c6a94b6e4aab502f9b88dd3ff664bd90b25839Aurimas Liutikas    final PrivateHandler mPrivateHandler;
72fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    private final ProviderCallback mProviderCallback;
73fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
74e2c6a94b6e4aab502f9b88dd3ff664bd90b25839Aurimas Liutikas    MediaRouteProvider mProvider;
7511417b1cfde8f1749905f2d735623af9214148afJeff Brown    private MediaRouteDiscoveryRequest mCompositeDiscoveryRequest;
76fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
77fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    /**
78fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown     * The {@link Intent} that must be declared as handled by the service.
79fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown     * Put this in your manifest.
80fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown     */
813efa63d3b896244713e84acbb5945562dce41d77Jeff Brown    public static final String SERVICE_INTERFACE = MediaRouteProviderProtocol.SERVICE_INTERFACE;
82fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
83fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    /*
84fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown     * Private messages used internally.  (Yes, you can renumber these.)
85fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown     */
86fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
87e2c6a94b6e4aab502f9b88dd3ff664bd90b25839Aurimas Liutikas    static final int PRIVATE_MSG_CLIENT_DIED = 1;
88fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
89fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    /**
90fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown     * Creates a media route provider service.
91fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown     */
92fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    public MediaRouteProviderService() {
93fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        mReceiveHandler = new ReceiveHandler(this);
94fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        mReceiveMessenger = new Messenger(mReceiveHandler);
95fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        mPrivateHandler = new PrivateHandler();
96fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        mProviderCallback = new ProviderCallback();
97fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    }
98fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
99fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    /**
100fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown     * Called by the system when it is time to create the media route provider.
101fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown     *
102fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown     * @return The media route provider offered by this service, or null if
103fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown     * this service has decided not to offer a media route provider.
104fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown     */
105fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    public abstract MediaRouteProvider onCreateMediaRouteProvider();
106fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
107fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    /**
108fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown     * Gets the media route provider offered by this service.
109fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown     *
110fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown     * @return The media route provider offered by this service, or null if
111fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown     * it has not yet been created.
112fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown     *
113fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown     * @see #onCreateMediaRouteProvider()
114fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown     */
115fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    public MediaRouteProvider getMediaRouteProvider() {
116fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        return mProvider;
117fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    }
118fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
119fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    @Override
120fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    public IBinder onBind(Intent intent) {
121fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        if (intent.getAction().equals(SERVICE_INTERFACE)) {
122fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            if (mProvider == null) {
123fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                MediaRouteProvider provider = onCreateMediaRouteProvider();
124fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                if (provider != null) {
125fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    String providerPackage = provider.getMetadata().getPackageName();
126fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    if (!providerPackage.equals(getPackageName())) {
127fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                        throw new IllegalStateException("onCreateMediaRouteProvider() returned "
128fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                                + "a provider whose package name does not match the package "
129fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                                + "name of the service.  A media route provider service can "
130fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                                + "only export its own media route providers.  "
131fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                                + "Provider package name: " + providerPackage
132fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                                + ".  Service package name: " + getPackageName() + ".");
133fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    }
134350ba6e4a1b5ec28721a098e50eaf6a508eb28f0Jeff Brown                    mProvider = provider;
13511417b1cfde8f1749905f2d735623af9214148afJeff Brown                    mProvider.setCallback(mProviderCallback);
136fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                }
137fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            }
138fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            if (mProvider != null) {
139fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                return mReceiveMessenger.getBinder();
140fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            }
141fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        }
142fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        return null;
143fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    }
144fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
14542c2365e621434a241af1909593b9c5d592b8ad7Sungsoo Lim    @Override
14642c2365e621434a241af1909593b9c5d592b8ad7Sungsoo Lim    public boolean onUnbind(Intent intent) {
14742c2365e621434a241af1909593b9c5d592b8ad7Sungsoo Lim        if (mProvider != null) {
14842c2365e621434a241af1909593b9c5d592b8ad7Sungsoo Lim            mProvider.setCallback(null);
14942c2365e621434a241af1909593b9c5d592b8ad7Sungsoo Lim        }
15042c2365e621434a241af1909593b9c5d592b8ad7Sungsoo Lim        return super.onUnbind(intent);
15142c2365e621434a241af1909593b9c5d592b8ad7Sungsoo Lim    }
15242c2365e621434a241af1909593b9c5d592b8ad7Sungsoo Lim
153e2c6a94b6e4aab502f9b88dd3ff664bd90b25839Aurimas Liutikas    boolean onRegisterClient(Messenger messenger, int requestId, int version) {
154fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        if (version >= CLIENT_VERSION_1) {
155fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            int index = findClient(messenger);
156fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            if (index < 0) {
157fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                ClientRecord client = new ClientRecord(messenger, version);
158fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                if (client.register()) {
159fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    mClients.add(client);
160fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    if (DEBUG) {
161fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                        Log.d(TAG, client + ": Registered, version=" + version);
162fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    }
163fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    if (requestId != 0) {
16411417b1cfde8f1749905f2d735623af9214148afJeff Brown                        MediaRouteProviderDescriptor descriptor = mProvider.getDescriptor();
165fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                        sendReply(messenger, SERVICE_MSG_REGISTERED,
166fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                                requestId, SERVICE_VERSION_CURRENT,
1679c83739aefcb1748551645a656bece0d864cef76Sungsoo Lim                                createDescriptorBundleForClient(descriptor, client), null);
168fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    }
169fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    return true;
170fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                }
171fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            }
172fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        }
173fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        return false;
174fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    }
175fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
176e2c6a94b6e4aab502f9b88dd3ff664bd90b25839Aurimas Liutikas    boolean onUnregisterClient(Messenger messenger, int requestId) {
177fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        int index = findClient(messenger);
178fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        if (index >= 0) {
179fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            ClientRecord client = mClients.remove(index);
180fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            if (DEBUG) {
181fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                Log.d(TAG, client + ": Unregistered");
182fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            }
183fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            client.dispose();
184fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            sendGenericSuccess(messenger, requestId);
185fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            return true;
186fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        }
187fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        return false;
188fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    }
189fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
190e2c6a94b6e4aab502f9b88dd3ff664bd90b25839Aurimas Liutikas    void onBinderDied(Messenger messenger) {
191fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        int index = findClient(messenger);
192fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        if (index >= 0) {
193fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            ClientRecord client = mClients.remove(index);
194fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            if (DEBUG) {
195fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                Log.d(TAG, client + ": Binder died");
196fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            }
197fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            client.dispose();
198fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        }
199fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    }
200fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
201e2c6a94b6e4aab502f9b88dd3ff664bd90b25839Aurimas Liutikas    boolean onCreateRouteController(Messenger messenger, int requestId,
2022f829125aef3796ca674d0ca5fccf9bd37b8417bSungsoo Lim            int controllerId, String routeId, String routeGroupId) {
203fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        ClientRecord client = getClient(messenger);
204fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        if (client != null) {
2052f829125aef3796ca674d0ca5fccf9bd37b8417bSungsoo Lim            if (client.createRouteController(routeId, routeGroupId, controllerId)) {
206fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                if (DEBUG) {
2072f829125aef3796ca674d0ca5fccf9bd37b8417bSungsoo Lim                    Log.d(TAG, client + ": Route controller created, controllerId=" + controllerId
2082f829125aef3796ca674d0ca5fccf9bd37b8417bSungsoo Lim                            + ", routeId=" + routeId + ", routeGroupId=" + routeGroupId);
209fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                }
210fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                sendGenericSuccess(messenger, requestId);
211fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                return true;
212fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            }
213fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        }
214fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        return false;
215fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    }
216fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
217e2c6a94b6e4aab502f9b88dd3ff664bd90b25839Aurimas Liutikas    boolean onReleaseRouteController(Messenger messenger, int requestId,
218fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            int controllerId) {
219fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        ClientRecord client = getClient(messenger);
220fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        if (client != null) {
221fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            if (client.releaseRouteController(controllerId)) {
222fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                if (DEBUG) {
223fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    Log.d(TAG, client + ": Route controller released"
224fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                            + ", controllerId=" + controllerId);
225fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                }
226fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                sendGenericSuccess(messenger, requestId);
227fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                return true;
228fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            }
229fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        }
230fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        return false;
231fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    }
232fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
233e2c6a94b6e4aab502f9b88dd3ff664bd90b25839Aurimas Liutikas    boolean onSelectRoute(Messenger messenger, int requestId,
234fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            int controllerId) {
235fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        ClientRecord client = getClient(messenger);
236fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        if (client != null) {
237fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            MediaRouteProvider.RouteController controller =
238fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    client.getRouteController(controllerId);
239fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            if (controller != null) {
240129abf73ce9be1bc172b945263c7975ad1a3006fJeff Brown                controller.onSelect();
241fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                if (DEBUG) {
242fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    Log.d(TAG, client + ": Route selected"
243fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                            + ", controllerId=" + controllerId);
244fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                }
245fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                sendGenericSuccess(messenger, requestId);
246fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                return true;
247fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            }
248fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        }
249fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        return false;
250fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    }
251fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
252e2c6a94b6e4aab502f9b88dd3ff664bd90b25839Aurimas Liutikas    boolean onUnselectRoute(Messenger messenger, int requestId,
25394be6100218126ce6a08bf1f56209578500b361fRoboErik            int controllerId, int reason) {
254fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        ClientRecord client = getClient(messenger);
255fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        if (client != null) {
256fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            MediaRouteProvider.RouteController controller =
257fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    client.getRouteController(controllerId);
258fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            if (controller != null) {
25994be6100218126ce6a08bf1f56209578500b361fRoboErik                controller.onUnselect(reason);
260fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                if (DEBUG) {
261fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    Log.d(TAG, client + ": Route unselected"
262fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                            + ", controllerId=" + controllerId);
263fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                }
264fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                sendGenericSuccess(messenger, requestId);
265fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                return true;
266fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            }
267fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        }
268fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        return false;
269fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    }
270fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
271e2c6a94b6e4aab502f9b88dd3ff664bd90b25839Aurimas Liutikas    boolean onSetRouteVolume(Messenger messenger, int requestId,
272fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            int controllerId, int volume) {
273fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        ClientRecord client = getClient(messenger);
274fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        if (client != null) {
275fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            MediaRouteProvider.RouteController controller =
276fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    client.getRouteController(controllerId);
277fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            if (controller != null) {
278129abf73ce9be1bc172b945263c7975ad1a3006fJeff Brown                controller.onSetVolume(volume);
279fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                if (DEBUG) {
280fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    Log.d(TAG, client + ": Route volume changed"
281fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                            + ", controllerId=" + controllerId + ", volume=" + volume);
282fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                }
283fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                sendGenericSuccess(messenger, requestId);
284fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                return true;
285fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            }
286fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        }
287fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        return false;
288fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    }
289fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
290e2c6a94b6e4aab502f9b88dd3ff664bd90b25839Aurimas Liutikas    boolean onUpdateRouteVolume(Messenger messenger, int requestId,
291fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            int controllerId, int delta) {
292fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        ClientRecord client = getClient(messenger);
293fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        if (client != null) {
294fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            MediaRouteProvider.RouteController controller =
295fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    client.getRouteController(controllerId);
296fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            if (controller != null) {
297129abf73ce9be1bc172b945263c7975ad1a3006fJeff Brown                controller.onUpdateVolume(delta);
298fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                if (DEBUG) {
299fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    Log.d(TAG, client + ": Route volume updated"
300fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                            + ", controllerId=" + controllerId + ", delta=" + delta);
301fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                }
302fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                sendGenericSuccess(messenger, requestId);
303fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                return true;
304fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            }
305fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        }
306fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        return false;
307fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    }
308fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
309e2c6a94b6e4aab502f9b88dd3ff664bd90b25839Aurimas Liutikas    boolean onRouteControlRequest(final Messenger messenger, final int requestId,
310fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            final int controllerId, final Intent intent) {
311fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        final ClientRecord client = getClient(messenger);
312fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        if (client != null) {
313fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            MediaRouteProvider.RouteController controller =
314fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    client.getRouteController(controllerId);
315fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            if (controller != null) {
316fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                MediaRouter.ControlRequestCallback callback = null;
317fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                if (requestId != 0) {
318fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    callback = new MediaRouter.ControlRequestCallback() {
319fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                        @Override
3203d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown                        public void onResult(Bundle data) {
3213d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown                            if (DEBUG) {
3223d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown                                Log.d(TAG, client + ": Route control request succeeded"
3233d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown                                        + ", controllerId=" + controllerId
3243d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown                                        + ", intent=" + intent
3253d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown                                        + ", data=" + data);
3263d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown                            }
3273d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown                            if (findClient(messenger) >= 0) {
3283d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown                                sendReply(messenger, SERVICE_MSG_CONTROL_REQUEST_SUCCEEDED,
3293d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown                                        requestId, 0, data, null);
3303d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown                            }
3313d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown                        }
3323d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown
3333d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown                        @Override
3343d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown                        public void onError(String error, Bundle data) {
335fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                            if (DEBUG) {
3363d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown                                Log.d(TAG, client + ": Route control request failed"
337fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                                        + ", controllerId=" + controllerId
338fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                                        + ", intent=" + intent
3393d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown                                        + ", error=" + error + ", data=" + data);
340fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                            }
341fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                            if (findClient(messenger) >= 0) {
3423d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown                                if (error != null) {
3433d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown                                    Bundle bundle = new Bundle();
3443d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown                                    bundle.putString(SERVICE_DATA_ERROR, error);
3453d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown                                    sendReply(messenger, SERVICE_MSG_CONTROL_REQUEST_FAILED,
3463d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown                                            requestId, 0, data, bundle);
3473d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown                                } else {
3483d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown                                    sendReply(messenger, SERVICE_MSG_CONTROL_REQUEST_FAILED,
3493d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown                                            requestId, 0, data, null);
3503d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown                                }
351fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                            }
352fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                        }
353fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    };
354fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                }
355129abf73ce9be1bc172b945263c7975ad1a3006fJeff Brown                if (controller.onControlRequest(intent, callback)) {
356fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    if (DEBUG) {
357fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                        Log.d(TAG, client + ": Route control request delivered"
358fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                                + ", controllerId=" + controllerId + ", intent=" + intent);
359fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    }
360fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    return true;
361fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                }
362fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            }
363fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        }
364fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        return false;
365fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    }
366fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
367e2c6a94b6e4aab502f9b88dd3ff664bd90b25839Aurimas Liutikas    boolean onSetDiscoveryRequest(Messenger messenger, int requestId,
36811417b1cfde8f1749905f2d735623af9214148afJeff Brown            MediaRouteDiscoveryRequest request) {
36928520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown        ClientRecord client = getClient(messenger);
37028520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown        if (client != null) {
37111417b1cfde8f1749905f2d735623af9214148afJeff Brown            boolean actuallyChanged = client.setDiscoveryRequest(request);
37228520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown            if (DEBUG) {
37311417b1cfde8f1749905f2d735623af9214148afJeff Brown                Log.d(TAG, client + ": Set discovery request, request=" + request
37411417b1cfde8f1749905f2d735623af9214148afJeff Brown                        + ", actuallyChanged=" + actuallyChanged
37511417b1cfde8f1749905f2d735623af9214148afJeff Brown                        + ", compositeDiscoveryRequest=" + mCompositeDiscoveryRequest);
37628520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown            }
37728520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown            sendGenericSuccess(messenger, requestId);
37828520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown            return true;
37928520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown        }
38028520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown        return false;
38128520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown    }
38228520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown
383e2c6a94b6e4aab502f9b88dd3ff664bd90b25839Aurimas Liutikas    void sendDescriptorChanged(MediaRouteProviderDescriptor descriptor) {
384fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        final int count = mClients.size();
385fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        for (int i = 0; i < count; i++) {
386fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            ClientRecord client = mClients.get(i);
387fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            sendReply(client.mMessenger, SERVICE_MSG_DESCRIPTOR_CHANGED, 0, 0,
3889c83739aefcb1748551645a656bece0d864cef76Sungsoo Lim                    createDescriptorBundleForClient(descriptor, client), null);
389fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            if (DEBUG) {
390fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                Log.d(TAG, client + ": Sent descriptor change event, descriptor=" + descriptor);
391fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            }
392fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        }
393fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    }
394fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
3959c83739aefcb1748551645a656bece0d864cef76Sungsoo Lim    private Bundle createDescriptorBundleForClient(MediaRouteProviderDescriptor descriptor,
3969c83739aefcb1748551645a656bece0d864cef76Sungsoo Lim            ClientRecord client) {
3979c83739aefcb1748551645a656bece0d864cef76Sungsoo Lim        if (descriptor == null) {
3989c83739aefcb1748551645a656bece0d864cef76Sungsoo Lim            return null;
3999c83739aefcb1748551645a656bece0d864cef76Sungsoo Lim        }
4009c83739aefcb1748551645a656bece0d864cef76Sungsoo Lim        List<MediaRouteDescriptor> routes = descriptor.getRoutes();
4019c83739aefcb1748551645a656bece0d864cef76Sungsoo Lim        for (int i = routes.size() - 1; i >= 0; i--) {
4029c83739aefcb1748551645a656bece0d864cef76Sungsoo Lim            if (client.mVersion < routes.get(i).getMinClientVersion()
4039c83739aefcb1748551645a656bece0d864cef76Sungsoo Lim                    || client.mVersion > routes.get(i).getMaxClientVersion()) {
4049c83739aefcb1748551645a656bece0d864cef76Sungsoo Lim                routes.remove(i);
4059c83739aefcb1748551645a656bece0d864cef76Sungsoo Lim            }
4069c83739aefcb1748551645a656bece0d864cef76Sungsoo Lim        }
4079c83739aefcb1748551645a656bece0d864cef76Sungsoo Lim
4089c83739aefcb1748551645a656bece0d864cef76Sungsoo Lim        // Keep the values of the bundle from descriptor excepts routes values.
4099c83739aefcb1748551645a656bece0d864cef76Sungsoo Lim        Bundle bundle = descriptor.asBundle();
4109c83739aefcb1748551645a656bece0d864cef76Sungsoo Lim        bundle.remove(MediaRouteProviderDescriptor.KEY_ROUTES);
4119c83739aefcb1748551645a656bece0d864cef76Sungsoo Lim        return new MediaRouteProviderDescriptor.Builder(
4129c83739aefcb1748551645a656bece0d864cef76Sungsoo Lim                MediaRouteProviderDescriptor.fromBundle(bundle))
4139c83739aefcb1748551645a656bece0d864cef76Sungsoo Lim                .addRoutes(routes).build().asBundle();
4149c83739aefcb1748551645a656bece0d864cef76Sungsoo Lim    }
4159c83739aefcb1748551645a656bece0d864cef76Sungsoo Lim
416e2c6a94b6e4aab502f9b88dd3ff664bd90b25839Aurimas Liutikas    boolean updateCompositeDiscoveryRequest() {
41711417b1cfde8f1749905f2d735623af9214148afJeff Brown        MediaRouteDiscoveryRequest composite = null;
41811417b1cfde8f1749905f2d735623af9214148afJeff Brown        MediaRouteSelector.Builder selectorBuilder = null;
41911417b1cfde8f1749905f2d735623af9214148afJeff Brown        boolean activeScan = false;
42011417b1cfde8f1749905f2d735623af9214148afJeff Brown        final int count = mClients.size();
42111417b1cfde8f1749905f2d735623af9214148afJeff Brown        for (int i = 0; i < count; i++) {
42211417b1cfde8f1749905f2d735623af9214148afJeff Brown            MediaRouteDiscoveryRequest request = mClients.get(i).mDiscoveryRequest;
42311417b1cfde8f1749905f2d735623af9214148afJeff Brown            if (request != null
42411417b1cfde8f1749905f2d735623af9214148afJeff Brown                    && (!request.getSelector().isEmpty() || request.isActiveScan())) {
42511417b1cfde8f1749905f2d735623af9214148afJeff Brown                activeScan |= request.isActiveScan();
42611417b1cfde8f1749905f2d735623af9214148afJeff Brown                if (composite == null) {
42711417b1cfde8f1749905f2d735623af9214148afJeff Brown                    composite = request;
42811417b1cfde8f1749905f2d735623af9214148afJeff Brown                } else {
42911417b1cfde8f1749905f2d735623af9214148afJeff Brown                    if (selectorBuilder == null) {
43011417b1cfde8f1749905f2d735623af9214148afJeff Brown                        selectorBuilder = new MediaRouteSelector.Builder(composite.getSelector());
43111417b1cfde8f1749905f2d735623af9214148afJeff Brown                    }
43211417b1cfde8f1749905f2d735623af9214148afJeff Brown                    selectorBuilder.addSelector(request.getSelector());
43311417b1cfde8f1749905f2d735623af9214148afJeff Brown                }
43411417b1cfde8f1749905f2d735623af9214148afJeff Brown            }
43511417b1cfde8f1749905f2d735623af9214148afJeff Brown        }
43611417b1cfde8f1749905f2d735623af9214148afJeff Brown        if (selectorBuilder != null) {
43711417b1cfde8f1749905f2d735623af9214148afJeff Brown            composite = new MediaRouteDiscoveryRequest(selectorBuilder.build(), activeScan);
43811417b1cfde8f1749905f2d735623af9214148afJeff Brown        }
43911417b1cfde8f1749905f2d735623af9214148afJeff Brown        if (mCompositeDiscoveryRequest != composite
44011417b1cfde8f1749905f2d735623af9214148afJeff Brown                && (mCompositeDiscoveryRequest == null
44111417b1cfde8f1749905f2d735623af9214148afJeff Brown                        || !mCompositeDiscoveryRequest.equals(composite))) {
44211417b1cfde8f1749905f2d735623af9214148afJeff Brown            mCompositeDiscoveryRequest = composite;
44311417b1cfde8f1749905f2d735623af9214148afJeff Brown            mProvider.setDiscoveryRequest(composite);
44411417b1cfde8f1749905f2d735623af9214148afJeff Brown            return true;
44511417b1cfde8f1749905f2d735623af9214148afJeff Brown        }
44611417b1cfde8f1749905f2d735623af9214148afJeff Brown        return false;
44711417b1cfde8f1749905f2d735623af9214148afJeff Brown    }
44811417b1cfde8f1749905f2d735623af9214148afJeff Brown
449fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    private ClientRecord getClient(Messenger messenger) {
450fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        int index = findClient(messenger);
451fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        return index >= 0 ? mClients.get(index) : null;
452fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    }
453fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
454e2c6a94b6e4aab502f9b88dd3ff664bd90b25839Aurimas Liutikas    int findClient(Messenger messenger) {
455fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        final int count = mClients.size();
456fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        for (int i = 0; i < count; i++) {
457fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            ClientRecord client = mClients.get(i);
458fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            if (client.hasMessenger(messenger)) {
459fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                return i;
460fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            }
461fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        }
462fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        return -1;
463fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    }
464fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
465e2c6a94b6e4aab502f9b88dd3ff664bd90b25839Aurimas Liutikas    static void sendGenericFailure(Messenger messenger, int requestId) {
466fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        if (requestId != 0) {
467fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            sendReply(messenger, SERVICE_MSG_GENERIC_FAILURE, requestId, 0, null, null);
468fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        }
469fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    }
470fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
471fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    private static void sendGenericSuccess(Messenger messenger, int requestId) {
472fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        if (requestId != 0) {
473fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            sendReply(messenger, SERVICE_MSG_GENERIC_SUCCESS, requestId, 0, null, null);
474fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        }
475fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    }
476fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
477e2c6a94b6e4aab502f9b88dd3ff664bd90b25839Aurimas Liutikas    static void sendReply(Messenger messenger, int what,
478fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            int requestId, int arg, Object obj, Bundle data) {
479fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        Message msg = Message.obtain();
480fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        msg.what = what;
481fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        msg.arg1 = requestId;
482fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        msg.arg2 = arg;
483fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        msg.obj = obj;
484fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        msg.setData(data);
485fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        try {
486fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            messenger.send(msg);
487fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        } catch (DeadObjectException ex) {
488fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            // The client died.
489fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        } catch (RemoteException ex) {
490fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            Log.e(TAG, "Could not send message to " + getClientId(messenger), ex);
491fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        }
492fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    }
493fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
494e2c6a94b6e4aab502f9b88dd3ff664bd90b25839Aurimas Liutikas    static String getClientId(Messenger messenger) {
495fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        return "Client connection " + messenger.getBinder().toString();
496fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    }
497fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
498fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    private final class PrivateHandler extends Handler {
499e2c6a94b6e4aab502f9b88dd3ff664bd90b25839Aurimas Liutikas        PrivateHandler() {
500e2c6a94b6e4aab502f9b88dd3ff664bd90b25839Aurimas Liutikas        }
501e2c6a94b6e4aab502f9b88dd3ff664bd90b25839Aurimas Liutikas
502fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        @Override
503fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        public void handleMessage(Message msg) {
504fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            switch (msg.what) {
505fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                case PRIVATE_MSG_CLIENT_DIED:
506fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    onBinderDied((Messenger)msg.obj);
507fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    break;
508fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            }
509fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        }
510fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    }
511fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
512fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    private final class ProviderCallback extends MediaRouteProvider.Callback {
513e2c6a94b6e4aab502f9b88dd3ff664bd90b25839Aurimas Liutikas        ProviderCallback() {
514e2c6a94b6e4aab502f9b88dd3ff664bd90b25839Aurimas Liutikas        }
515e2c6a94b6e4aab502f9b88dd3ff664bd90b25839Aurimas Liutikas
516fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        @Override
517fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        public void onDescriptorChanged(MediaRouteProvider provider,
51811417b1cfde8f1749905f2d735623af9214148afJeff Brown                MediaRouteProviderDescriptor descriptor) {
519fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            sendDescriptorChanged(descriptor);
520fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        }
521fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    }
522fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
523fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    private final class ClientRecord implements DeathRecipient {
524fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        public final Messenger mMessenger;
525fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        public final int mVersion;
52611417b1cfde8f1749905f2d735623af9214148afJeff Brown        public MediaRouteDiscoveryRequest mDiscoveryRequest;
527fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
528fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        private final SparseArray<MediaRouteProvider.RouteController> mControllers =
529fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                new SparseArray<MediaRouteProvider.RouteController>();
530fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
531fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        public ClientRecord(Messenger messenger, int version) {
532fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            mMessenger = messenger;
533fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            mVersion = version;
534fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        }
535fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
536fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        public boolean register() {
537fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            try {
538fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                mMessenger.getBinder().linkToDeath(this, 0);
539fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                return true;
540fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            } catch (RemoteException ex) {
541fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                binderDied();
542fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            }
543fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            return false;
544fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        }
545fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
546fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        public void dispose() {
547fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            int count = mControllers.size();
548fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            for (int i = 0; i < count; i++) {
549129abf73ce9be1bc172b945263c7975ad1a3006fJeff Brown                mControllers.valueAt(i).onRelease();
550fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            }
551fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            mControllers.clear();
552fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
553fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            mMessenger.getBinder().unlinkToDeath(this, 0);
55428520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown
55511417b1cfde8f1749905f2d735623af9214148afJeff Brown            setDiscoveryRequest(null);
556fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        }
557fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
558fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        public boolean hasMessenger(Messenger other) {
559fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            return mMessenger.getBinder() == other.getBinder();
560fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        }
561fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
5622f829125aef3796ca674d0ca5fccf9bd37b8417bSungsoo Lim        public boolean createRouteController(String routeId, String routeGroupId,
5632f829125aef3796ca674d0ca5fccf9bd37b8417bSungsoo Lim                int controllerId) {
564fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            if (mControllers.indexOfKey(controllerId) < 0) {
5652f829125aef3796ca674d0ca5fccf9bd37b8417bSungsoo Lim                MediaRouteProvider.RouteController controller = routeGroupId == null
5662f829125aef3796ca674d0ca5fccf9bd37b8417bSungsoo Lim                        ? mProvider.onCreateRouteController(routeId)
5672f829125aef3796ca674d0ca5fccf9bd37b8417bSungsoo Lim                        : mProvider.onCreateRouteController(routeId, routeGroupId);
568ae161a4d000a10dafd844d17145de631933f21f3Jeff Brown                if (controller != null) {
569ae161a4d000a10dafd844d17145de631933f21f3Jeff Brown                    mControllers.put(controllerId, controller);
570ae161a4d000a10dafd844d17145de631933f21f3Jeff Brown                    return true;
571ae161a4d000a10dafd844d17145de631933f21f3Jeff Brown                }
572fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            }
573fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            return false;
574fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        }
575fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
576fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        public boolean releaseRouteController(int controllerId) {
577fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            MediaRouteProvider.RouteController controller = mControllers.get(controllerId);
578fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            if (controller != null) {
579fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                mControllers.remove(controllerId);
580129abf73ce9be1bc172b945263c7975ad1a3006fJeff Brown                controller.onRelease();
581fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                return true;
582fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            }
583fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            return false;
584fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        }
585fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
586fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        public MediaRouteProvider.RouteController getRouteController(int controllerId) {
587fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            return mControllers.get(controllerId);
588fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        }
589fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
59011417b1cfde8f1749905f2d735623af9214148afJeff Brown        public boolean setDiscoveryRequest(MediaRouteDiscoveryRequest request) {
59111417b1cfde8f1749905f2d735623af9214148afJeff Brown            if (mDiscoveryRequest != request
59211417b1cfde8f1749905f2d735623af9214148afJeff Brown                    && (mDiscoveryRequest == null || !mDiscoveryRequest.equals(request))) {
59311417b1cfde8f1749905f2d735623af9214148afJeff Brown                mDiscoveryRequest = request;
59411417b1cfde8f1749905f2d735623af9214148afJeff Brown                return updateCompositeDiscoveryRequest();
59528520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown            }
59628520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown            return false;
59728520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown        }
59828520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown
59928520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown        // Runs on a binder thread.
600fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        @Override
601fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        public void binderDied() {
602fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            mPrivateHandler.obtainMessage(PRIVATE_MSG_CLIENT_DIED, mMessenger).sendToTarget();
603fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        }
604fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
605fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        @Override
606fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        public String toString() {
607fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            return getClientId(mMessenger);
608fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        }
609fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    }
610fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
611fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    /**
612fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown     * Handler that receives messages from clients.
613fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown     * <p>
614fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown     * This inner class is static and only retains a weak reference to the service
615fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown     * to prevent the service from being leaked in case one of the clients is holding an
616fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown     * active reference to the server's messenger.
617fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown     * </p><p>
618fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown     * This handler should not be used to handle any messages other than those
619fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown     * that come from the client.
620fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown     * </p>
621fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown     */
622fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    private static final class ReceiveHandler extends Handler {
623fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        private final WeakReference<MediaRouteProviderService> mServiceRef;
624fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
625fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        public ReceiveHandler(MediaRouteProviderService service) {
626fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            mServiceRef = new WeakReference<MediaRouteProviderService>(service);
627fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        }
628fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
629fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        @Override
630fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        public void handleMessage(Message msg) {
631fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            final Messenger messenger = msg.replyTo;
632fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            if (isValidRemoteMessenger(messenger)) {
633fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                final int what = msg.what;
634fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                final int requestId = msg.arg1;
635fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                final int arg = msg.arg2;
636fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                final Object obj = msg.obj;
637fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                final Bundle data = msg.peekData();
638fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                if (!processMessage(what, messenger, requestId, arg, obj, data)) {
639fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    if (DEBUG) {
640fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                        Log.d(TAG, getClientId(messenger) + ": Message failed, what=" + what
641fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                                + ", requestId=" + requestId + ", arg=" + arg
642fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                                + ", obj=" + obj + ", data=" + data);
643fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    }
644fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    sendGenericFailure(messenger, requestId);
645fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                }
646fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            } else {
647fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                if (DEBUG) {
648fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    Log.d(TAG, "Ignoring message without valid reply messenger.");
649fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                }
650fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            }
651fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        }
652fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
653fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        private boolean processMessage(int what,
654fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                Messenger messenger, int requestId, int arg, Object obj, Bundle data) {
655fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            MediaRouteProviderService service = mServiceRef.get();
656fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            if (service != null) {
657fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                switch (what) {
658fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    case CLIENT_MSG_REGISTER:
659fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                        return service.onRegisterClient(messenger, requestId, arg);
660fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
661fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    case CLIENT_MSG_UNREGISTER:
662fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                        return service.onUnregisterClient(messenger, requestId);
663fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
664fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    case CLIENT_MSG_CREATE_ROUTE_CONTROLLER: {
665fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                        String routeId = data.getString(CLIENT_DATA_ROUTE_ID);
6662f829125aef3796ca674d0ca5fccf9bd37b8417bSungsoo Lim                        String routeGroupId = data.getString(CLIENT_DATA_ROUTE_GROUP_ID);
667fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                        if (routeId != null) {
668fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                            return service.onCreateRouteController(
6692f829125aef3796ca674d0ca5fccf9bd37b8417bSungsoo Lim                                    messenger, requestId, arg, routeId, routeGroupId);
670fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                        }
671fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                        break;
672fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    }
673fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
674fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    case CLIENT_MSG_RELEASE_ROUTE_CONTROLLER:
675fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                        return service.onReleaseRouteController(messenger, requestId, arg);
676fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
677fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    case CLIENT_MSG_SELECT_ROUTE:
678fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                        return service.onSelectRoute(messenger, requestId, arg);
679fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
680fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    case CLIENT_MSG_UNSELECT_ROUTE:
68194be6100218126ce6a08bf1f56209578500b361fRoboErik                        int reason = data == null ?
68294be6100218126ce6a08bf1f56209578500b361fRoboErik                                MediaRouter.UNSELECT_REASON_UNKNOWN
68394be6100218126ce6a08bf1f56209578500b361fRoboErik                                : data.getInt(CLIENT_DATA_UNSELECT_REASON,
68494be6100218126ce6a08bf1f56209578500b361fRoboErik                                        MediaRouter.UNSELECT_REASON_UNKNOWN);
68594be6100218126ce6a08bf1f56209578500b361fRoboErik                        return service.onUnselectRoute(messenger, requestId, arg, reason);
686fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
687fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    case CLIENT_MSG_SET_ROUTE_VOLUME: {
688fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                        int volume = data.getInt(CLIENT_DATA_VOLUME, -1);
689fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                        if (volume >= 0) {
690fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                            return service.onSetRouteVolume(
691fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                                    messenger, requestId, arg, volume);
692fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                        }
693fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                        break;
694fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    }
695fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
696fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    case CLIENT_MSG_UPDATE_ROUTE_VOLUME: {
697fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                        int delta = data.getInt(CLIENT_DATA_VOLUME, 0);
698fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                        if (delta != 0) {
699fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                            return service.onUpdateRouteVolume(
700fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                                    messenger, requestId, arg, delta);
701fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                        }
702fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                        break;
703fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    }
704fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
705fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    case CLIENT_MSG_ROUTE_CONTROL_REQUEST:
706fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                        if (obj instanceof Intent) {
707fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                            return service.onRouteControlRequest(
708fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                                    messenger, requestId, arg, (Intent)obj);
709fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                        }
710fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                        break;
71128520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown
71211417b1cfde8f1749905f2d735623af9214148afJeff Brown                    case CLIENT_MSG_SET_DISCOVERY_REQUEST: {
713f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown                        if (obj == null || obj instanceof Bundle) {
71411417b1cfde8f1749905f2d735623af9214148afJeff Brown                            MediaRouteDiscoveryRequest request =
71511417b1cfde8f1749905f2d735623af9214148afJeff Brown                                    MediaRouteDiscoveryRequest.fromBundle((Bundle)obj);
71611417b1cfde8f1749905f2d735623af9214148afJeff Brown                            return service.onSetDiscoveryRequest(
717f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown                                    messenger, requestId,
718f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown                                    request != null && request.isValid() ? request : null);
71911417b1cfde8f1749905f2d735623af9214148afJeff Brown                        }
72011417b1cfde8f1749905f2d735623af9214148afJeff Brown                    }
721fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                }
722fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            }
723fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            return false;
724fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        }
725fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    }
726fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown}
727