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;
21fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brownimport android.os.Handler;
22fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brownimport android.os.IBinder;
23fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brownimport android.os.IBinder.DeathRecipient;
24fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brownimport android.os.Bundle;
25fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brownimport android.os.DeadObjectException;
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;
34fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
353efa63d3b896244713e84acbb5945562dce41d77Jeff Brownimport static android.support.v7.media.MediaRouteProviderProtocol.*;
363efa63d3b896244713e84acbb5945562dce41d77Jeff Brown
37fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown/**
38fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * Base class for media route provider services.
39fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * <p>
40d8e02077fc00aabc7432246e2301626fb342129dSungsoo Lim * A media router will bind to media route provider services when a callback is added via
41d8e02077fc00aabc7432246e2301626fb342129dSungsoo Lim * {@link MediaRouter#addCallback(MediaRouteSelector, MediaRouter.Callback, int)} with a discovery
42d8e02077fc00aabc7432246e2301626fb342129dSungsoo Lim * flag: {@link MediaRouter#CALLBACK_FLAG_REQUEST_DISCOVERY},
43d8e02077fc00aabc7432246e2301626fb342129dSungsoo Lim * {@link MediaRouter#CALLBACK_FLAG_FORCE_DISCOVERY}, or
44d8e02077fc00aabc7432246e2301626fb342129dSungsoo Lim * {@link MediaRouter#CALLBACK_FLAG_PERFORM_ACTIVE_SCAN}, and will unbind when the callback
45d8e02077fc00aabc7432246e2301626fb342129dSungsoo Lim * is removed via {@link MediaRouter#removeCallback(MediaRouter.Callback)}.
46d8e02077fc00aabc7432246e2301626fb342129dSungsoo Lim * </p><p>
47fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * To implement your own media route provider service, extend this class and
48fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * override the {@link #onCreateMediaRouteProvider} method to return an
49fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * instance of your {@link MediaRouteProvider}.
50fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * </p><p>
51fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * Declare your media route provider service in your application manifest
52fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * like this:
53fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * </p>
54fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * <pre>
55fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown *   &lt;service android:name=".MyMediaRouteProviderService"
56fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown *           android:label="@string/my_media_route_provider_service">
57fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown *       &lt;intent-filter>
58fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown *           &lt;action android:name="android.media.MediaRouteProviderService" />
59fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown *       &lt;/intent-filter>
60fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown *   &lt;/service>
61fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * </pre>
62fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown */
63fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brownpublic abstract class MediaRouteProviderService extends Service {
64f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown    private static final String TAG = "MediaRouteProviderSrv"; // max. 23 chars
65f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
66fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
67fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    private final ArrayList<ClientRecord> mClients = new ArrayList<ClientRecord>();
68fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    private final ReceiveHandler mReceiveHandler;
69fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    private final Messenger mReceiveMessenger;
70fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    private final PrivateHandler mPrivateHandler;
71fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    private final ProviderCallback mProviderCallback;
72fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
73fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    private MediaRouteProvider mProvider;
7411417b1cfde8f1749905f2d735623af9214148afJeff Brown    private MediaRouteDiscoveryRequest mCompositeDiscoveryRequest;
75fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
76fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    /**
77fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown     * The {@link Intent} that must be declared as handled by the service.
78fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown     * Put this in your manifest.
79fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown     */
803efa63d3b896244713e84acbb5945562dce41d77Jeff Brown    public static final String SERVICE_INTERFACE = MediaRouteProviderProtocol.SERVICE_INTERFACE;
81fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
82fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    /*
83fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown     * Private messages used internally.  (Yes, you can renumber these.)
84fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown     */
85fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
86fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    private static final int PRIVATE_MSG_CLIENT_DIED = 1;
87fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
88fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    /**
89fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown     * Creates a media route provider service.
90fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown     */
91fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    public MediaRouteProviderService() {
92fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        mReceiveHandler = new ReceiveHandler(this);
93fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        mReceiveMessenger = new Messenger(mReceiveHandler);
94fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        mPrivateHandler = new PrivateHandler();
95fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        mProviderCallback = new ProviderCallback();
96fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    }
97fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
98fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    /**
99fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown     * Called by the system when it is time to create the media route provider.
100fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown     *
101fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown     * @return The media route provider offered by this service, or null if
102fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown     * this service has decided not to offer a media route provider.
103fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown     */
104fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    public abstract MediaRouteProvider onCreateMediaRouteProvider();
105fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
106fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    /**
107fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown     * Gets the media route provider offered by this service.
108fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown     *
109fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown     * @return The media route provider offered by this service, or null if
110fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown     * it has not yet been created.
111fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown     *
112fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown     * @see #onCreateMediaRouteProvider()
113fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown     */
114fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    public MediaRouteProvider getMediaRouteProvider() {
115fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        return mProvider;
116fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    }
117fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
118fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    @Override
119fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    public IBinder onBind(Intent intent) {
120fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        if (intent.getAction().equals(SERVICE_INTERFACE)) {
121fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            if (mProvider == null) {
122fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                MediaRouteProvider provider = onCreateMediaRouteProvider();
123fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                if (provider != null) {
124fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    String providerPackage = provider.getMetadata().getPackageName();
125fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    if (!providerPackage.equals(getPackageName())) {
126fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                        throw new IllegalStateException("onCreateMediaRouteProvider() returned "
127fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                                + "a provider whose package name does not match the package "
128fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                                + "name of the service.  A media route provider service can "
129fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                                + "only export its own media route providers.  "
130fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                                + "Provider package name: " + providerPackage
131fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                                + ".  Service package name: " + getPackageName() + ".");
132fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    }
133350ba6e4a1b5ec28721a098e50eaf6a508eb28f0Jeff Brown                    mProvider = provider;
13411417b1cfde8f1749905f2d735623af9214148afJeff Brown                    mProvider.setCallback(mProviderCallback);
135fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                }
136fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            }
137fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            if (mProvider != null) {
138fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                return mReceiveMessenger.getBinder();
139fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            }
140fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        }
141fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        return null;
142fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    }
143fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
14442c2365e621434a241af1909593b9c5d592b8ad7Sungsoo Lim    @Override
14542c2365e621434a241af1909593b9c5d592b8ad7Sungsoo Lim    public boolean onUnbind(Intent intent) {
14642c2365e621434a241af1909593b9c5d592b8ad7Sungsoo Lim        if (mProvider != null) {
14742c2365e621434a241af1909593b9c5d592b8ad7Sungsoo Lim            mProvider.setCallback(null);
14842c2365e621434a241af1909593b9c5d592b8ad7Sungsoo Lim        }
14942c2365e621434a241af1909593b9c5d592b8ad7Sungsoo Lim        return super.onUnbind(intent);
15042c2365e621434a241af1909593b9c5d592b8ad7Sungsoo Lim    }
15142c2365e621434a241af1909593b9c5d592b8ad7Sungsoo Lim
152fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    private boolean onRegisterClient(Messenger messenger, int requestId, int version) {
153fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        if (version >= CLIENT_VERSION_1) {
154fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            int index = findClient(messenger);
155fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            if (index < 0) {
156fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                ClientRecord client = new ClientRecord(messenger, version);
157fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                if (client.register()) {
158fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    mClients.add(client);
159fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    if (DEBUG) {
160fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                        Log.d(TAG, client + ": Registered, version=" + version);
161fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    }
162fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    if (requestId != 0) {
16311417b1cfde8f1749905f2d735623af9214148afJeff Brown                        MediaRouteProviderDescriptor descriptor = mProvider.getDescriptor();
164fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                        sendReply(messenger, SERVICE_MSG_REGISTERED,
165fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                                requestId, SERVICE_VERSION_CURRENT,
166fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                                descriptor != null ? descriptor.asBundle() : null, null);
167fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    }
168fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    return true;
169fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                }
170fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            }
171fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        }
172fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        return false;
173fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    }
174fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
175fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    private boolean onUnregisterClient(Messenger messenger, int requestId) {
176fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        int index = findClient(messenger);
177fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        if (index >= 0) {
178fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            ClientRecord client = mClients.remove(index);
179fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            if (DEBUG) {
180fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                Log.d(TAG, client + ": Unregistered");
181fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            }
182fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            client.dispose();
183fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            sendGenericSuccess(messenger, requestId);
184fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            return true;
185fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        }
186fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        return false;
187fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    }
188fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
189fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    private void onBinderDied(Messenger messenger) {
190fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        int index = findClient(messenger);
191fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        if (index >= 0) {
192fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            ClientRecord client = mClients.remove(index);
193fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            if (DEBUG) {
194fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                Log.d(TAG, client + ": Binder died");
195fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            }
196fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            client.dispose();
197fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        }
198fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    }
199fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
200fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    private boolean onCreateRouteController(Messenger messenger, int requestId,
201fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            int controllerId, String routeId) {
202fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        ClientRecord client = getClient(messenger);
203fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        if (client != null) {
204fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            if (client.createRouteController(routeId, controllerId)) {
205fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                if (DEBUG) {
206fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    Log.d(TAG, client + ": Route controller created"
207fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                            + ", controllerId=" + controllerId + ", routeId=" + routeId);
208fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                }
209fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                sendGenericSuccess(messenger, requestId);
210fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                return true;
211fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            }
212fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        }
213fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        return false;
214fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    }
215fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
216fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    private boolean onReleaseRouteController(Messenger messenger, int requestId,
217fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            int controllerId) {
218fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        ClientRecord client = getClient(messenger);
219fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        if (client != null) {
220fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            if (client.releaseRouteController(controllerId)) {
221fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                if (DEBUG) {
222fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    Log.d(TAG, client + ": Route controller released"
223fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                            + ", controllerId=" + controllerId);
224fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                }
225fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                sendGenericSuccess(messenger, requestId);
226fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                return true;
227fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            }
228fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        }
229fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        return false;
230fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    }
231fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
232fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    private boolean onSelectRoute(Messenger messenger, int requestId,
233fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            int controllerId) {
234fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        ClientRecord client = getClient(messenger);
235fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        if (client != null) {
236fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            MediaRouteProvider.RouteController controller =
237fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    client.getRouteController(controllerId);
238fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            if (controller != null) {
239129abf73ce9be1bc172b945263c7975ad1a3006fJeff Brown                controller.onSelect();
240fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                if (DEBUG) {
241fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    Log.d(TAG, client + ": Route selected"
242fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                            + ", controllerId=" + controllerId);
243fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                }
244fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                sendGenericSuccess(messenger, requestId);
245fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                return true;
246fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            }
247fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        }
248fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        return false;
249fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    }
250fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
251fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    private boolean onUnselectRoute(Messenger messenger, int requestId,
25294be6100218126ce6a08bf1f56209578500b361fRoboErik            int controllerId, int reason) {
253fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        ClientRecord client = getClient(messenger);
254fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        if (client != null) {
255fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            MediaRouteProvider.RouteController controller =
256fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    client.getRouteController(controllerId);
257fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            if (controller != null) {
25894be6100218126ce6a08bf1f56209578500b361fRoboErik                controller.onUnselect(reason);
259fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                if (DEBUG) {
260fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    Log.d(TAG, client + ": Route unselected"
261fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                            + ", controllerId=" + controllerId);
262fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                }
263fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                sendGenericSuccess(messenger, requestId);
264fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                return true;
265fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            }
266fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        }
267fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        return false;
268fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    }
269fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
270fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    private boolean onSetRouteVolume(Messenger messenger, int requestId,
271fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            int controllerId, int volume) {
272fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        ClientRecord client = getClient(messenger);
273fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        if (client != null) {
274fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            MediaRouteProvider.RouteController controller =
275fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    client.getRouteController(controllerId);
276fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            if (controller != null) {
277129abf73ce9be1bc172b945263c7975ad1a3006fJeff Brown                controller.onSetVolume(volume);
278fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                if (DEBUG) {
279fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    Log.d(TAG, client + ": Route volume changed"
280fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                            + ", controllerId=" + controllerId + ", volume=" + volume);
281fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                }
282fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                sendGenericSuccess(messenger, requestId);
283fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                return true;
284fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            }
285fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        }
286fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        return false;
287fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    }
288fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
289fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    private boolean onUpdateRouteVolume(Messenger messenger, int requestId,
290fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            int controllerId, int delta) {
291fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        ClientRecord client = getClient(messenger);
292fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        if (client != null) {
293fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            MediaRouteProvider.RouteController controller =
294fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    client.getRouteController(controllerId);
295fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            if (controller != null) {
296129abf73ce9be1bc172b945263c7975ad1a3006fJeff Brown                controller.onUpdateVolume(delta);
297fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                if (DEBUG) {
298fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    Log.d(TAG, client + ": Route volume updated"
299fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                            + ", controllerId=" + controllerId + ", delta=" + delta);
300fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                }
301fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                sendGenericSuccess(messenger, requestId);
302fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                return true;
303fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            }
304fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        }
305fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        return false;
306fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    }
307fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
308fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    private boolean onRouteControlRequest(final Messenger messenger, final int requestId,
309fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            final int controllerId, final Intent intent) {
310fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        final ClientRecord client = getClient(messenger);
311fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        if (client != null) {
312fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            MediaRouteProvider.RouteController controller =
313fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    client.getRouteController(controllerId);
314fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            if (controller != null) {
315fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                MediaRouter.ControlRequestCallback callback = null;
316fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                if (requestId != 0) {
317fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    callback = new MediaRouter.ControlRequestCallback() {
318fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                        @Override
3193d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown                        public void onResult(Bundle data) {
3203d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown                            if (DEBUG) {
3213d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown                                Log.d(TAG, client + ": Route control request succeeded"
3223d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown                                        + ", controllerId=" + controllerId
3233d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown                                        + ", intent=" + intent
3243d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown                                        + ", data=" + data);
3253d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown                            }
3263d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown                            if (findClient(messenger) >= 0) {
3273d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown                                sendReply(messenger, SERVICE_MSG_CONTROL_REQUEST_SUCCEEDED,
3283d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown                                        requestId, 0, data, null);
3293d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown                            }
3303d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown                        }
3313d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown
3323d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown                        @Override
3333d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown                        public void onError(String error, Bundle data) {
334fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                            if (DEBUG) {
3353d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown                                Log.d(TAG, client + ": Route control request failed"
336fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                                        + ", controllerId=" + controllerId
337fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                                        + ", intent=" + intent
3383d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown                                        + ", error=" + error + ", data=" + data);
339fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                            }
340fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                            if (findClient(messenger) >= 0) {
3413d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown                                if (error != null) {
3423d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown                                    Bundle bundle = new Bundle();
3433d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown                                    bundle.putString(SERVICE_DATA_ERROR, error);
3443d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown                                    sendReply(messenger, SERVICE_MSG_CONTROL_REQUEST_FAILED,
3453d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown                                            requestId, 0, data, bundle);
3463d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown                                } else {
3473d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown                                    sendReply(messenger, SERVICE_MSG_CONTROL_REQUEST_FAILED,
3483d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown                                            requestId, 0, data, null);
3493d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown                                }
350fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                            }
351fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                        }
352fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    };
353fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                }
354129abf73ce9be1bc172b945263c7975ad1a3006fJeff Brown                if (controller.onControlRequest(intent, callback)) {
355fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    if (DEBUG) {
356fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                        Log.d(TAG, client + ": Route control request delivered"
357fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                                + ", controllerId=" + controllerId + ", intent=" + intent);
358fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    }
359fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    return true;
360fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                }
361fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            }
362fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        }
363fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        return false;
364fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    }
365fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
36611417b1cfde8f1749905f2d735623af9214148afJeff Brown    private boolean onSetDiscoveryRequest(Messenger messenger, int requestId,
36711417b1cfde8f1749905f2d735623af9214148afJeff Brown            MediaRouteDiscoveryRequest request) {
36828520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown        ClientRecord client = getClient(messenger);
36928520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown        if (client != null) {
37011417b1cfde8f1749905f2d735623af9214148afJeff Brown            boolean actuallyChanged = client.setDiscoveryRequest(request);
37128520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown            if (DEBUG) {
37211417b1cfde8f1749905f2d735623af9214148afJeff Brown                Log.d(TAG, client + ": Set discovery request, request=" + request
37311417b1cfde8f1749905f2d735623af9214148afJeff Brown                        + ", actuallyChanged=" + actuallyChanged
37411417b1cfde8f1749905f2d735623af9214148afJeff Brown                        + ", compositeDiscoveryRequest=" + mCompositeDiscoveryRequest);
37528520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown            }
37628520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown            sendGenericSuccess(messenger, requestId);
37728520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown            return true;
37828520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown        }
37928520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown        return false;
38028520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown    }
38128520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown
38211417b1cfde8f1749905f2d735623af9214148afJeff Brown    private void sendDescriptorChanged(MediaRouteProviderDescriptor descriptor) {
383fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        Bundle descriptorBundle = descriptor != null ? descriptor.asBundle() : null;
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,
388fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    descriptorBundle, 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
39511417b1cfde8f1749905f2d735623af9214148afJeff Brown    private boolean updateCompositeDiscoveryRequest() {
39611417b1cfde8f1749905f2d735623af9214148afJeff Brown        MediaRouteDiscoveryRequest composite = null;
39711417b1cfde8f1749905f2d735623af9214148afJeff Brown        MediaRouteSelector.Builder selectorBuilder = null;
39811417b1cfde8f1749905f2d735623af9214148afJeff Brown        boolean activeScan = false;
39911417b1cfde8f1749905f2d735623af9214148afJeff Brown        final int count = mClients.size();
40011417b1cfde8f1749905f2d735623af9214148afJeff Brown        for (int i = 0; i < count; i++) {
40111417b1cfde8f1749905f2d735623af9214148afJeff Brown            MediaRouteDiscoveryRequest request = mClients.get(i).mDiscoveryRequest;
40211417b1cfde8f1749905f2d735623af9214148afJeff Brown            if (request != null
40311417b1cfde8f1749905f2d735623af9214148afJeff Brown                    && (!request.getSelector().isEmpty() || request.isActiveScan())) {
40411417b1cfde8f1749905f2d735623af9214148afJeff Brown                activeScan |= request.isActiveScan();
40511417b1cfde8f1749905f2d735623af9214148afJeff Brown                if (composite == null) {
40611417b1cfde8f1749905f2d735623af9214148afJeff Brown                    composite = request;
40711417b1cfde8f1749905f2d735623af9214148afJeff Brown                } else {
40811417b1cfde8f1749905f2d735623af9214148afJeff Brown                    if (selectorBuilder == null) {
40911417b1cfde8f1749905f2d735623af9214148afJeff Brown                        selectorBuilder = new MediaRouteSelector.Builder(composite.getSelector());
41011417b1cfde8f1749905f2d735623af9214148afJeff Brown                    }
41111417b1cfde8f1749905f2d735623af9214148afJeff Brown                    selectorBuilder.addSelector(request.getSelector());
41211417b1cfde8f1749905f2d735623af9214148afJeff Brown                }
41311417b1cfde8f1749905f2d735623af9214148afJeff Brown            }
41411417b1cfde8f1749905f2d735623af9214148afJeff Brown        }
41511417b1cfde8f1749905f2d735623af9214148afJeff Brown        if (selectorBuilder != null) {
41611417b1cfde8f1749905f2d735623af9214148afJeff Brown            composite = new MediaRouteDiscoveryRequest(selectorBuilder.build(), activeScan);
41711417b1cfde8f1749905f2d735623af9214148afJeff Brown        }
41811417b1cfde8f1749905f2d735623af9214148afJeff Brown        if (mCompositeDiscoveryRequest != composite
41911417b1cfde8f1749905f2d735623af9214148afJeff Brown                && (mCompositeDiscoveryRequest == null
42011417b1cfde8f1749905f2d735623af9214148afJeff Brown                        || !mCompositeDiscoveryRequest.equals(composite))) {
42111417b1cfde8f1749905f2d735623af9214148afJeff Brown            mCompositeDiscoveryRequest = composite;
42211417b1cfde8f1749905f2d735623af9214148afJeff Brown            mProvider.setDiscoveryRequest(composite);
42311417b1cfde8f1749905f2d735623af9214148afJeff Brown            return true;
42411417b1cfde8f1749905f2d735623af9214148afJeff Brown        }
42511417b1cfde8f1749905f2d735623af9214148afJeff Brown        return false;
42611417b1cfde8f1749905f2d735623af9214148afJeff Brown    }
42711417b1cfde8f1749905f2d735623af9214148afJeff Brown
428fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    private ClientRecord getClient(Messenger messenger) {
429fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        int index = findClient(messenger);
430fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        return index >= 0 ? mClients.get(index) : null;
431fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    }
432fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
433fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    private int findClient(Messenger messenger) {
434fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        final int count = mClients.size();
435fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        for (int i = 0; i < count; i++) {
436fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            ClientRecord client = mClients.get(i);
437fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            if (client.hasMessenger(messenger)) {
438fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                return i;
439fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            }
440fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        }
441fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        return -1;
442fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    }
443fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
444fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    private static void sendGenericFailure(Messenger messenger, int requestId) {
445fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        if (requestId != 0) {
446fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            sendReply(messenger, SERVICE_MSG_GENERIC_FAILURE, requestId, 0, null, null);
447fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        }
448fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    }
449fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
450fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    private static void sendGenericSuccess(Messenger messenger, int requestId) {
451fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        if (requestId != 0) {
452fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            sendReply(messenger, SERVICE_MSG_GENERIC_SUCCESS, requestId, 0, null, null);
453fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        }
454fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    }
455fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
456fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    private static void sendReply(Messenger messenger, int what,
457fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            int requestId, int arg, Object obj, Bundle data) {
458fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        Message msg = Message.obtain();
459fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        msg.what = what;
460fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        msg.arg1 = requestId;
461fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        msg.arg2 = arg;
462fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        msg.obj = obj;
463fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        msg.setData(data);
464fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        try {
465fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            messenger.send(msg);
466fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        } catch (DeadObjectException ex) {
467fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            // The client died.
468fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        } catch (RemoteException ex) {
469fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            Log.e(TAG, "Could not send message to " + getClientId(messenger), ex);
470fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        }
471fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    }
472fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
473fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    private static String getClientId(Messenger messenger) {
474fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        return "Client connection " + messenger.getBinder().toString();
475fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    }
476fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
477fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    private final class PrivateHandler extends Handler {
478fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        @Override
479fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        public void handleMessage(Message msg) {
480fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            switch (msg.what) {
481fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                case PRIVATE_MSG_CLIENT_DIED:
482fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    onBinderDied((Messenger)msg.obj);
483fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    break;
484fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            }
485fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        }
486fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    }
487fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
488fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    private final class ProviderCallback extends MediaRouteProvider.Callback {
489fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        @Override
490fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        public void onDescriptorChanged(MediaRouteProvider provider,
49111417b1cfde8f1749905f2d735623af9214148afJeff Brown                MediaRouteProviderDescriptor descriptor) {
492fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            sendDescriptorChanged(descriptor);
493fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        }
494fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    }
495fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
496fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    private final class ClientRecord implements DeathRecipient {
497fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        public final Messenger mMessenger;
498fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        public final int mVersion;
49911417b1cfde8f1749905f2d735623af9214148afJeff Brown        public MediaRouteDiscoveryRequest mDiscoveryRequest;
500fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
501fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        private final SparseArray<MediaRouteProvider.RouteController> mControllers =
502fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                new SparseArray<MediaRouteProvider.RouteController>();
503fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
504fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        public ClientRecord(Messenger messenger, int version) {
505fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            mMessenger = messenger;
506fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            mVersion = version;
507fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        }
508fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
509fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        public boolean register() {
510fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            try {
511fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                mMessenger.getBinder().linkToDeath(this, 0);
512fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                return true;
513fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            } catch (RemoteException ex) {
514fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                binderDied();
515fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            }
516fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            return false;
517fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        }
518fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
519fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        public void dispose() {
520fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            int count = mControllers.size();
521fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            for (int i = 0; i < count; i++) {
522129abf73ce9be1bc172b945263c7975ad1a3006fJeff Brown                mControllers.valueAt(i).onRelease();
523fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            }
524fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            mControllers.clear();
525fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
526fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            mMessenger.getBinder().unlinkToDeath(this, 0);
52728520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown
52811417b1cfde8f1749905f2d735623af9214148afJeff Brown            setDiscoveryRequest(null);
529fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        }
530fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
531fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        public boolean hasMessenger(Messenger other) {
532fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            return mMessenger.getBinder() == other.getBinder();
533fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        }
534fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
535fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        public boolean createRouteController(String routeId, int controllerId) {
536fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            if (mControllers.indexOfKey(controllerId) < 0) {
537fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                MediaRouteProvider.RouteController controller =
538fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                        mProvider.onCreateRouteController(routeId);
539ae161a4d000a10dafd844d17145de631933f21f3Jeff Brown                if (controller != null) {
540ae161a4d000a10dafd844d17145de631933f21f3Jeff Brown                    mControllers.put(controllerId, controller);
541ae161a4d000a10dafd844d17145de631933f21f3Jeff Brown                    return true;
542ae161a4d000a10dafd844d17145de631933f21f3Jeff Brown                }
543fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            }
544fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            return false;
545fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        }
546fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
547fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        public boolean releaseRouteController(int controllerId) {
548fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            MediaRouteProvider.RouteController controller = mControllers.get(controllerId);
549fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            if (controller != null) {
550fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                mControllers.remove(controllerId);
551129abf73ce9be1bc172b945263c7975ad1a3006fJeff Brown                controller.onRelease();
552fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                return true;
553fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            }
554fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            return false;
555fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        }
556fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
557fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        public MediaRouteProvider.RouteController getRouteController(int controllerId) {
558fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            return mControllers.get(controllerId);
559fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        }
560fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
56111417b1cfde8f1749905f2d735623af9214148afJeff Brown        public boolean setDiscoveryRequest(MediaRouteDiscoveryRequest request) {
56211417b1cfde8f1749905f2d735623af9214148afJeff Brown            if (mDiscoveryRequest != request
56311417b1cfde8f1749905f2d735623af9214148afJeff Brown                    && (mDiscoveryRequest == null || !mDiscoveryRequest.equals(request))) {
56411417b1cfde8f1749905f2d735623af9214148afJeff Brown                mDiscoveryRequest = request;
56511417b1cfde8f1749905f2d735623af9214148afJeff Brown                return updateCompositeDiscoveryRequest();
56628520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown            }
56728520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown            return false;
56828520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown        }
56928520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown
57028520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown        // Runs on a binder thread.
571fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        @Override
572fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        public void binderDied() {
573fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            mPrivateHandler.obtainMessage(PRIVATE_MSG_CLIENT_DIED, mMessenger).sendToTarget();
574fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        }
575fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
576fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        @Override
577fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        public String toString() {
578fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            return getClientId(mMessenger);
579fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        }
580fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    }
581fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
582fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    /**
583fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown     * Handler that receives messages from clients.
584fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown     * <p>
585fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown     * This inner class is static and only retains a weak reference to the service
586fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown     * to prevent the service from being leaked in case one of the clients is holding an
587fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown     * active reference to the server's messenger.
588fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown     * </p><p>
589fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown     * This handler should not be used to handle any messages other than those
590fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown     * that come from the client.
591fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown     * </p>
592fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown     */
593fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    private static final class ReceiveHandler extends Handler {
594fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        private final WeakReference<MediaRouteProviderService> mServiceRef;
595fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
596fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        public ReceiveHandler(MediaRouteProviderService service) {
597fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            mServiceRef = new WeakReference<MediaRouteProviderService>(service);
598fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        }
599fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
600fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        @Override
601fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        public void handleMessage(Message msg) {
602fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            final Messenger messenger = msg.replyTo;
603fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            if (isValidRemoteMessenger(messenger)) {
604fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                final int what = msg.what;
605fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                final int requestId = msg.arg1;
606fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                final int arg = msg.arg2;
607fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                final Object obj = msg.obj;
608fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                final Bundle data = msg.peekData();
609fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                if (!processMessage(what, messenger, requestId, arg, obj, data)) {
610fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    if (DEBUG) {
611fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                        Log.d(TAG, getClientId(messenger) + ": Message failed, what=" + what
612fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                                + ", requestId=" + requestId + ", arg=" + arg
613fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                                + ", obj=" + obj + ", data=" + data);
614fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    }
615fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    sendGenericFailure(messenger, requestId);
616fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                }
617fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            } else {
618fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                if (DEBUG) {
619fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    Log.d(TAG, "Ignoring message without valid reply messenger.");
620fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                }
621fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            }
622fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        }
623fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
624fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        private boolean processMessage(int what,
625fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                Messenger messenger, int requestId, int arg, Object obj, Bundle data) {
626fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            MediaRouteProviderService service = mServiceRef.get();
627fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            if (service != null) {
628fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                switch (what) {
629fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    case CLIENT_MSG_REGISTER:
630fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                        return service.onRegisterClient(messenger, requestId, arg);
631fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
632fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    case CLIENT_MSG_UNREGISTER:
633fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                        return service.onUnregisterClient(messenger, requestId);
634fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
635fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    case CLIENT_MSG_CREATE_ROUTE_CONTROLLER: {
636fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                        String routeId = data.getString(CLIENT_DATA_ROUTE_ID);
637fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                        if (routeId != null) {
638fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                            return service.onCreateRouteController(
639fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                                    messenger, requestId, arg, routeId);
640fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                        }
641fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                        break;
642fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    }
643fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
644fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    case CLIENT_MSG_RELEASE_ROUTE_CONTROLLER:
645fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                        return service.onReleaseRouteController(messenger, requestId, arg);
646fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
647fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    case CLIENT_MSG_SELECT_ROUTE:
648fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                        return service.onSelectRoute(messenger, requestId, arg);
649fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
650fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    case CLIENT_MSG_UNSELECT_ROUTE:
65194be6100218126ce6a08bf1f56209578500b361fRoboErik                        int reason = data == null ?
65294be6100218126ce6a08bf1f56209578500b361fRoboErik                                MediaRouter.UNSELECT_REASON_UNKNOWN
65394be6100218126ce6a08bf1f56209578500b361fRoboErik                                : data.getInt(CLIENT_DATA_UNSELECT_REASON,
65494be6100218126ce6a08bf1f56209578500b361fRoboErik                                        MediaRouter.UNSELECT_REASON_UNKNOWN);
65594be6100218126ce6a08bf1f56209578500b361fRoboErik                        return service.onUnselectRoute(messenger, requestId, arg, reason);
656fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
657fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    case CLIENT_MSG_SET_ROUTE_VOLUME: {
658fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                        int volume = data.getInt(CLIENT_DATA_VOLUME, -1);
659fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                        if (volume >= 0) {
660fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                            return service.onSetRouteVolume(
661fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                                    messenger, requestId, arg, volume);
662fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                        }
663fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                        break;
664fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    }
665fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
666fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    case CLIENT_MSG_UPDATE_ROUTE_VOLUME: {
667fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                        int delta = data.getInt(CLIENT_DATA_VOLUME, 0);
668fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                        if (delta != 0) {
669fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                            return service.onUpdateRouteVolume(
670fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                                    messenger, requestId, arg, delta);
671fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                        }
672fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                        break;
673fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    }
674fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
675fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    case CLIENT_MSG_ROUTE_CONTROL_REQUEST:
676fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                        if (obj instanceof Intent) {
677fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                            return service.onRouteControlRequest(
678fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                                    messenger, requestId, arg, (Intent)obj);
679fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                        }
680fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                        break;
68128520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown
68211417b1cfde8f1749905f2d735623af9214148afJeff Brown                    case CLIENT_MSG_SET_DISCOVERY_REQUEST: {
683f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown                        if (obj == null || obj instanceof Bundle) {
68411417b1cfde8f1749905f2d735623af9214148afJeff Brown                            MediaRouteDiscoveryRequest request =
68511417b1cfde8f1749905f2d735623af9214148afJeff Brown                                    MediaRouteDiscoveryRequest.fromBundle((Bundle)obj);
68611417b1cfde8f1749905f2d735623af9214148afJeff Brown                            return service.onSetDiscoveryRequest(
687f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown                                    messenger, requestId,
688f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown                                    request != null && request.isValid() ? request : null);
68911417b1cfde8f1749905f2d735623af9214148afJeff Brown                        }
69011417b1cfde8f1749905f2d735623af9214148afJeff Brown                    }
691fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                }
692fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            }
693fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            return false;
694fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        }
695fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    }
696fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown}
697