MediaRouteProviderService.java revision 94be6100218126ce6a08bf1f56209578500b361f
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>
40fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * To implement your own media route provider service, extend this class and
41fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * override the {@link #onCreateMediaRouteProvider} method to return an
42fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * instance of your {@link MediaRouteProvider}.
43fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * </p><p>
44fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * Declare your media route provider service in your application manifest
45fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * like this:
46fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * </p>
47fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * <pre>
48fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown *   &lt;service android:name=".MyMediaRouteProviderService"
49fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown *           android:label="@string/my_media_route_provider_service">
50fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown *       &lt;intent-filter>
51fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown *           &lt;action android:name="android.media.MediaRouteProviderService" />
52fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown *       &lt;/intent-filter>
53fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown *   &lt;/service>
54fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * </pre>
55fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown */
56fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brownpublic abstract class MediaRouteProviderService extends Service {
57f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown    private static final String TAG = "MediaRouteProviderSrv"; // max. 23 chars
58f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
59fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
60fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    private final ArrayList<ClientRecord> mClients = new ArrayList<ClientRecord>();
61fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    private final ReceiveHandler mReceiveHandler;
62fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    private final Messenger mReceiveMessenger;
63fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    private final PrivateHandler mPrivateHandler;
64fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    private final ProviderCallback mProviderCallback;
65fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
66fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    private MediaRouteProvider mProvider;
6711417b1cfde8f1749905f2d735623af9214148afJeff Brown    private MediaRouteDiscoveryRequest mCompositeDiscoveryRequest;
68fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
69fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    /**
70fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown     * The {@link Intent} that must be declared as handled by the service.
71fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown     * Put this in your manifest.
72fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown     */
733efa63d3b896244713e84acbb5945562dce41d77Jeff Brown    public static final String SERVICE_INTERFACE = MediaRouteProviderProtocol.SERVICE_INTERFACE;
74fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
75fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    /*
76fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown     * Private messages used internally.  (Yes, you can renumber these.)
77fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown     */
78fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
79fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    private static final int PRIVATE_MSG_CLIENT_DIED = 1;
80fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
81fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    /**
82fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown     * Creates a media route provider service.
83fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown     */
84fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    public MediaRouteProviderService() {
85fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        mReceiveHandler = new ReceiveHandler(this);
86fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        mReceiveMessenger = new Messenger(mReceiveHandler);
87fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        mPrivateHandler = new PrivateHandler();
88fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        mProviderCallback = new ProviderCallback();
89fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    }
90fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
91fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    /**
92fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown     * Called by the system when it is time to create the media route provider.
93fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown     *
94fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown     * @return The media route provider offered by this service, or null if
95fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown     * this service has decided not to offer a media route provider.
96fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown     */
97fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    public abstract MediaRouteProvider onCreateMediaRouteProvider();
98fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
99fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    /**
100fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown     * Gets the media route provider offered by this service.
101fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown     *
102fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown     * @return The media route provider offered by this service, or null if
103fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown     * it has not yet been created.
104fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown     *
105fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown     * @see #onCreateMediaRouteProvider()
106fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown     */
107fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    public MediaRouteProvider getMediaRouteProvider() {
108fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        return mProvider;
109fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    }
110fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
111fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    @Override
112fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    public IBinder onBind(Intent intent) {
113fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        if (intent.getAction().equals(SERVICE_INTERFACE)) {
114fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            if (mProvider == null) {
115fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                MediaRouteProvider provider = onCreateMediaRouteProvider();
116fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                if (provider != null) {
117fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    String providerPackage = provider.getMetadata().getPackageName();
118fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    if (!providerPackage.equals(getPackageName())) {
119fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                        throw new IllegalStateException("onCreateMediaRouteProvider() returned "
120fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                                + "a provider whose package name does not match the package "
121fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                                + "name of the service.  A media route provider service can "
122fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                                + "only export its own media route providers.  "
123fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                                + "Provider package name: " + providerPackage
124fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                                + ".  Service package name: " + getPackageName() + ".");
125fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    }
126350ba6e4a1b5ec28721a098e50eaf6a508eb28f0Jeff Brown                    mProvider = provider;
12711417b1cfde8f1749905f2d735623af9214148afJeff Brown                    mProvider.setCallback(mProviderCallback);
128fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                }
129fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            }
130fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            if (mProvider != null) {
131fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                return mReceiveMessenger.getBinder();
132fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            }
133fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        }
134fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        return null;
135fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    }
136fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
137fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    private boolean onRegisterClient(Messenger messenger, int requestId, int version) {
138fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        if (version >= CLIENT_VERSION_1) {
139fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            int index = findClient(messenger);
140fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            if (index < 0) {
141fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                ClientRecord client = new ClientRecord(messenger, version);
142fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                if (client.register()) {
143fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    mClients.add(client);
144fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    if (DEBUG) {
145fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                        Log.d(TAG, client + ": Registered, version=" + version);
146fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    }
147fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    if (requestId != 0) {
14811417b1cfde8f1749905f2d735623af9214148afJeff Brown                        MediaRouteProviderDescriptor descriptor = mProvider.getDescriptor();
149fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                        sendReply(messenger, SERVICE_MSG_REGISTERED,
150fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                                requestId, SERVICE_VERSION_CURRENT,
151fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                                descriptor != null ? descriptor.asBundle() : null, null);
152fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    }
153fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    return true;
154fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                }
155fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            }
156fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        }
157fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        return false;
158fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    }
159fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
160fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    private boolean onUnregisterClient(Messenger messenger, int requestId) {
161fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        int index = findClient(messenger);
162fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        if (index >= 0) {
163fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            ClientRecord client = mClients.remove(index);
164fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            if (DEBUG) {
165fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                Log.d(TAG, client + ": Unregistered");
166fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            }
167fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            client.dispose();
168fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            sendGenericSuccess(messenger, requestId);
169fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            return true;
170fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        }
171fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        return false;
172fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    }
173fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
174fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    private void onBinderDied(Messenger messenger) {
175fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        int index = findClient(messenger);
176fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        if (index >= 0) {
177fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            ClientRecord client = mClients.remove(index);
178fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            if (DEBUG) {
179fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                Log.d(TAG, client + ": Binder died");
180fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            }
181fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            client.dispose();
182fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        }
183fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    }
184fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
185fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    private boolean onCreateRouteController(Messenger messenger, int requestId,
186fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            int controllerId, String routeId) {
187fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        ClientRecord client = getClient(messenger);
188fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        if (client != null) {
189fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            if (client.createRouteController(routeId, controllerId)) {
190fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                if (DEBUG) {
191fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    Log.d(TAG, client + ": Route controller created"
192fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                            + ", controllerId=" + controllerId + ", routeId=" + routeId);
193fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                }
194fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                sendGenericSuccess(messenger, requestId);
195fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                return true;
196fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            }
197fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        }
198fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        return false;
199fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    }
200fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
201fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    private boolean onReleaseRouteController(Messenger messenger, int requestId,
202fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            int controllerId) {
203fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        ClientRecord client = getClient(messenger);
204fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        if (client != null) {
205fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            if (client.releaseRouteController(controllerId)) {
206fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                if (DEBUG) {
207fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    Log.d(TAG, client + ": Route controller released"
208fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                            + ", controllerId=" + controllerId);
209fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                }
210fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                sendGenericSuccess(messenger, requestId);
211fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                return true;
212fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            }
213fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        }
214fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        return false;
215fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    }
216fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
217fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    private boolean onSelectRoute(Messenger messenger, int requestId,
218fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            int controllerId) {
219fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        ClientRecord client = getClient(messenger);
220fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        if (client != null) {
221fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            MediaRouteProvider.RouteController controller =
222fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    client.getRouteController(controllerId);
223fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            if (controller != null) {
224129abf73ce9be1bc172b945263c7975ad1a3006fJeff Brown                controller.onSelect();
225fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                if (DEBUG) {
226fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    Log.d(TAG, client + ": Route selected"
227fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                            + ", controllerId=" + controllerId);
228fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                }
229fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                sendGenericSuccess(messenger, requestId);
230fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                return true;
231fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            }
232fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        }
233fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        return false;
234fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    }
235fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
236fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    private boolean onUnselectRoute(Messenger messenger, int requestId,
23794be6100218126ce6a08bf1f56209578500b361fRoboErik            int controllerId, int reason) {
238fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        ClientRecord client = getClient(messenger);
239fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        if (client != null) {
240fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            MediaRouteProvider.RouteController controller =
241fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    client.getRouteController(controllerId);
242fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            if (controller != null) {
24394be6100218126ce6a08bf1f56209578500b361fRoboErik                controller.onUnselect(reason);
244fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                if (DEBUG) {
245fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    Log.d(TAG, client + ": Route unselected"
246fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                            + ", controllerId=" + controllerId);
247fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                }
248fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                sendGenericSuccess(messenger, requestId);
249fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                return true;
250fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            }
251fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        }
252fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        return false;
253fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    }
254fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
255fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    private boolean onSetRouteVolume(Messenger messenger, int requestId,
256fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            int controllerId, int volume) {
257fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        ClientRecord client = getClient(messenger);
258fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        if (client != null) {
259fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            MediaRouteProvider.RouteController controller =
260fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    client.getRouteController(controllerId);
261fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            if (controller != null) {
262129abf73ce9be1bc172b945263c7975ad1a3006fJeff Brown                controller.onSetVolume(volume);
263fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                if (DEBUG) {
264fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    Log.d(TAG, client + ": Route volume changed"
265fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                            + ", controllerId=" + controllerId + ", volume=" + volume);
266fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                }
267fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                sendGenericSuccess(messenger, requestId);
268fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                return true;
269fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            }
270fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        }
271fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        return false;
272fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    }
273fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
274fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    private boolean onUpdateRouteVolume(Messenger messenger, int requestId,
275fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            int controllerId, int delta) {
276fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        ClientRecord client = getClient(messenger);
277fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        if (client != null) {
278fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            MediaRouteProvider.RouteController controller =
279fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    client.getRouteController(controllerId);
280fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            if (controller != null) {
281129abf73ce9be1bc172b945263c7975ad1a3006fJeff Brown                controller.onUpdateVolume(delta);
282fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                if (DEBUG) {
283fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    Log.d(TAG, client + ": Route volume updated"
284fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                            + ", controllerId=" + controllerId + ", delta=" + delta);
285fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                }
286fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                sendGenericSuccess(messenger, requestId);
287fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                return true;
288fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            }
289fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        }
290fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        return false;
291fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    }
292fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
293fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    private boolean onRouteControlRequest(final Messenger messenger, final int requestId,
294fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            final int controllerId, final Intent intent) {
295fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        final ClientRecord client = getClient(messenger);
296fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        if (client != null) {
297fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            MediaRouteProvider.RouteController controller =
298fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    client.getRouteController(controllerId);
299fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            if (controller != null) {
300fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                MediaRouter.ControlRequestCallback callback = null;
301fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                if (requestId != 0) {
302fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    callback = new MediaRouter.ControlRequestCallback() {
303fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                        @Override
3043d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown                        public void onResult(Bundle data) {
3053d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown                            if (DEBUG) {
3063d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown                                Log.d(TAG, client + ": Route control request succeeded"
3073d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown                                        + ", controllerId=" + controllerId
3083d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown                                        + ", intent=" + intent
3093d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown                                        + ", data=" + data);
3103d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown                            }
3113d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown                            if (findClient(messenger) >= 0) {
3123d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown                                sendReply(messenger, SERVICE_MSG_CONTROL_REQUEST_SUCCEEDED,
3133d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown                                        requestId, 0, data, null);
3143d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown                            }
3153d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown                        }
3163d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown
3173d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown                        @Override
3183d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown                        public void onError(String error, Bundle data) {
319fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                            if (DEBUG) {
3203d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown                                Log.d(TAG, client + ": Route control request failed"
321fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                                        + ", controllerId=" + controllerId
322fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                                        + ", intent=" + intent
3233d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown                                        + ", error=" + error + ", data=" + data);
324fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                            }
325fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                            if (findClient(messenger) >= 0) {
3263d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown                                if (error != null) {
3273d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown                                    Bundle bundle = new Bundle();
3283d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown                                    bundle.putString(SERVICE_DATA_ERROR, error);
3293d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown                                    sendReply(messenger, SERVICE_MSG_CONTROL_REQUEST_FAILED,
3303d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown                                            requestId, 0, data, bundle);
3313d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown                                } else {
3323d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown                                    sendReply(messenger, SERVICE_MSG_CONTROL_REQUEST_FAILED,
3333d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown                                            requestId, 0, data, null);
3343d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown                                }
335fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                            }
336fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                        }
337fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    };
338fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                }
339129abf73ce9be1bc172b945263c7975ad1a3006fJeff Brown                if (controller.onControlRequest(intent, callback)) {
340fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    if (DEBUG) {
341fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                        Log.d(TAG, client + ": Route control request delivered"
342fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                                + ", controllerId=" + controllerId + ", intent=" + intent);
343fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    }
344fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    return true;
345fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                }
346fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            }
347fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        }
348fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        return false;
349fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    }
350fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
35111417b1cfde8f1749905f2d735623af9214148afJeff Brown    private boolean onSetDiscoveryRequest(Messenger messenger, int requestId,
35211417b1cfde8f1749905f2d735623af9214148afJeff Brown            MediaRouteDiscoveryRequest request) {
35328520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown        ClientRecord client = getClient(messenger);
35428520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown        if (client != null) {
35511417b1cfde8f1749905f2d735623af9214148afJeff Brown            boolean actuallyChanged = client.setDiscoveryRequest(request);
35628520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown            if (DEBUG) {
35711417b1cfde8f1749905f2d735623af9214148afJeff Brown                Log.d(TAG, client + ": Set discovery request, request=" + request
35811417b1cfde8f1749905f2d735623af9214148afJeff Brown                        + ", actuallyChanged=" + actuallyChanged
35911417b1cfde8f1749905f2d735623af9214148afJeff Brown                        + ", compositeDiscoveryRequest=" + mCompositeDiscoveryRequest);
36028520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown            }
36128520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown            sendGenericSuccess(messenger, requestId);
36228520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown            return true;
36328520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown        }
36428520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown        return false;
36528520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown    }
36628520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown
36711417b1cfde8f1749905f2d735623af9214148afJeff Brown    private void sendDescriptorChanged(MediaRouteProviderDescriptor descriptor) {
368fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        Bundle descriptorBundle = descriptor != null ? descriptor.asBundle() : null;
369fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        final int count = mClients.size();
370fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        for (int i = 0; i < count; i++) {
371fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            ClientRecord client = mClients.get(i);
372fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            sendReply(client.mMessenger, SERVICE_MSG_DESCRIPTOR_CHANGED, 0, 0,
373fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    descriptorBundle, null);
374fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            if (DEBUG) {
375fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                Log.d(TAG, client + ": Sent descriptor change event, descriptor=" + descriptor);
376fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            }
377fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        }
378fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    }
379fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
38011417b1cfde8f1749905f2d735623af9214148afJeff Brown    private boolean updateCompositeDiscoveryRequest() {
38111417b1cfde8f1749905f2d735623af9214148afJeff Brown        MediaRouteDiscoveryRequest composite = null;
38211417b1cfde8f1749905f2d735623af9214148afJeff Brown        MediaRouteSelector.Builder selectorBuilder = null;
38311417b1cfde8f1749905f2d735623af9214148afJeff Brown        boolean activeScan = false;
38411417b1cfde8f1749905f2d735623af9214148afJeff Brown        final int count = mClients.size();
38511417b1cfde8f1749905f2d735623af9214148afJeff Brown        for (int i = 0; i < count; i++) {
38611417b1cfde8f1749905f2d735623af9214148afJeff Brown            MediaRouteDiscoveryRequest request = mClients.get(i).mDiscoveryRequest;
38711417b1cfde8f1749905f2d735623af9214148afJeff Brown            if (request != null
38811417b1cfde8f1749905f2d735623af9214148afJeff Brown                    && (!request.getSelector().isEmpty() || request.isActiveScan())) {
38911417b1cfde8f1749905f2d735623af9214148afJeff Brown                activeScan |= request.isActiveScan();
39011417b1cfde8f1749905f2d735623af9214148afJeff Brown                if (composite == null) {
39111417b1cfde8f1749905f2d735623af9214148afJeff Brown                    composite = request;
39211417b1cfde8f1749905f2d735623af9214148afJeff Brown                } else {
39311417b1cfde8f1749905f2d735623af9214148afJeff Brown                    if (selectorBuilder == null) {
39411417b1cfde8f1749905f2d735623af9214148afJeff Brown                        selectorBuilder = new MediaRouteSelector.Builder(composite.getSelector());
39511417b1cfde8f1749905f2d735623af9214148afJeff Brown                    }
39611417b1cfde8f1749905f2d735623af9214148afJeff Brown                    selectorBuilder.addSelector(request.getSelector());
39711417b1cfde8f1749905f2d735623af9214148afJeff Brown                }
39811417b1cfde8f1749905f2d735623af9214148afJeff Brown            }
39911417b1cfde8f1749905f2d735623af9214148afJeff Brown        }
40011417b1cfde8f1749905f2d735623af9214148afJeff Brown        if (selectorBuilder != null) {
40111417b1cfde8f1749905f2d735623af9214148afJeff Brown            composite = new MediaRouteDiscoveryRequest(selectorBuilder.build(), activeScan);
40211417b1cfde8f1749905f2d735623af9214148afJeff Brown        }
40311417b1cfde8f1749905f2d735623af9214148afJeff Brown        if (mCompositeDiscoveryRequest != composite
40411417b1cfde8f1749905f2d735623af9214148afJeff Brown                && (mCompositeDiscoveryRequest == null
40511417b1cfde8f1749905f2d735623af9214148afJeff Brown                        || !mCompositeDiscoveryRequest.equals(composite))) {
40611417b1cfde8f1749905f2d735623af9214148afJeff Brown            mCompositeDiscoveryRequest = composite;
40711417b1cfde8f1749905f2d735623af9214148afJeff Brown            mProvider.setDiscoveryRequest(composite);
40811417b1cfde8f1749905f2d735623af9214148afJeff Brown            return true;
40911417b1cfde8f1749905f2d735623af9214148afJeff Brown        }
41011417b1cfde8f1749905f2d735623af9214148afJeff Brown        return false;
41111417b1cfde8f1749905f2d735623af9214148afJeff Brown    }
41211417b1cfde8f1749905f2d735623af9214148afJeff Brown
413fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    private ClientRecord getClient(Messenger messenger) {
414fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        int index = findClient(messenger);
415fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        return index >= 0 ? mClients.get(index) : null;
416fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    }
417fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
418fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    private int findClient(Messenger messenger) {
419fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        final int count = mClients.size();
420fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        for (int i = 0; i < count; i++) {
421fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            ClientRecord client = mClients.get(i);
422fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            if (client.hasMessenger(messenger)) {
423fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                return i;
424fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            }
425fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        }
426fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        return -1;
427fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    }
428fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
429fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    private static void sendGenericFailure(Messenger messenger, int requestId) {
430fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        if (requestId != 0) {
431fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            sendReply(messenger, SERVICE_MSG_GENERIC_FAILURE, requestId, 0, null, null);
432fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        }
433fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    }
434fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
435fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    private static void sendGenericSuccess(Messenger messenger, int requestId) {
436fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        if (requestId != 0) {
437fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            sendReply(messenger, SERVICE_MSG_GENERIC_SUCCESS, requestId, 0, null, null);
438fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        }
439fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    }
440fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
441fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    private static void sendReply(Messenger messenger, int what,
442fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            int requestId, int arg, Object obj, Bundle data) {
443fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        Message msg = Message.obtain();
444fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        msg.what = what;
445fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        msg.arg1 = requestId;
446fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        msg.arg2 = arg;
447fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        msg.obj = obj;
448fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        msg.setData(data);
449fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        try {
450fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            messenger.send(msg);
451fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        } catch (DeadObjectException ex) {
452fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            // The client died.
453fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        } catch (RemoteException ex) {
454fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            Log.e(TAG, "Could not send message to " + getClientId(messenger), ex);
455fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        }
456fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    }
457fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
458fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    private static String getClientId(Messenger messenger) {
459fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        return "Client connection " + messenger.getBinder().toString();
460fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    }
461fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
462fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    private final class PrivateHandler extends Handler {
463fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        @Override
464fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        public void handleMessage(Message msg) {
465fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            switch (msg.what) {
466fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                case PRIVATE_MSG_CLIENT_DIED:
467fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    onBinderDied((Messenger)msg.obj);
468fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    break;
469fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            }
470fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        }
471fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    }
472fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
473fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    private final class ProviderCallback extends MediaRouteProvider.Callback {
474fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        @Override
475fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        public void onDescriptorChanged(MediaRouteProvider provider,
47611417b1cfde8f1749905f2d735623af9214148afJeff Brown                MediaRouteProviderDescriptor descriptor) {
477fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            sendDescriptorChanged(descriptor);
478fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        }
479fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    }
480fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
481fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    private final class ClientRecord implements DeathRecipient {
482fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        public final Messenger mMessenger;
483fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        public final int mVersion;
48411417b1cfde8f1749905f2d735623af9214148afJeff Brown        public MediaRouteDiscoveryRequest mDiscoveryRequest;
485fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
486fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        private final SparseArray<MediaRouteProvider.RouteController> mControllers =
487fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                new SparseArray<MediaRouteProvider.RouteController>();
488fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
489fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        public ClientRecord(Messenger messenger, int version) {
490fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            mMessenger = messenger;
491fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            mVersion = version;
492fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        }
493fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
494fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        public boolean register() {
495fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            try {
496fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                mMessenger.getBinder().linkToDeath(this, 0);
497fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                return true;
498fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            } catch (RemoteException ex) {
499fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                binderDied();
500fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            }
501fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            return false;
502fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        }
503fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
504fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        public void dispose() {
505fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            int count = mControllers.size();
506fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            for (int i = 0; i < count; i++) {
507129abf73ce9be1bc172b945263c7975ad1a3006fJeff Brown                mControllers.valueAt(i).onRelease();
508fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            }
509fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            mControllers.clear();
510fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
511fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            mMessenger.getBinder().unlinkToDeath(this, 0);
51228520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown
51311417b1cfde8f1749905f2d735623af9214148afJeff Brown            setDiscoveryRequest(null);
514fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        }
515fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
516fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        public boolean hasMessenger(Messenger other) {
517fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            return mMessenger.getBinder() == other.getBinder();
518fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        }
519fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
520fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        public boolean createRouteController(String routeId, int controllerId) {
521fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            if (mControllers.indexOfKey(controllerId) < 0) {
522fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                MediaRouteProvider.RouteController controller =
523fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                        mProvider.onCreateRouteController(routeId);
524ae161a4d000a10dafd844d17145de631933f21f3Jeff Brown                if (controller != null) {
525ae161a4d000a10dafd844d17145de631933f21f3Jeff Brown                    mControllers.put(controllerId, controller);
526ae161a4d000a10dafd844d17145de631933f21f3Jeff Brown                    return true;
527ae161a4d000a10dafd844d17145de631933f21f3Jeff Brown                }
528fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            }
529fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            return false;
530fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        }
531fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
532fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        public boolean releaseRouteController(int controllerId) {
533fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            MediaRouteProvider.RouteController controller = mControllers.get(controllerId);
534fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            if (controller != null) {
535fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                mControllers.remove(controllerId);
536129abf73ce9be1bc172b945263c7975ad1a3006fJeff Brown                controller.onRelease();
537fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                return true;
538fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            }
539fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            return false;
540fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        }
541fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
542fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        public MediaRouteProvider.RouteController getRouteController(int controllerId) {
543fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            return mControllers.get(controllerId);
544fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        }
545fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
54611417b1cfde8f1749905f2d735623af9214148afJeff Brown        public boolean setDiscoveryRequest(MediaRouteDiscoveryRequest request) {
54711417b1cfde8f1749905f2d735623af9214148afJeff Brown            if (mDiscoveryRequest != request
54811417b1cfde8f1749905f2d735623af9214148afJeff Brown                    && (mDiscoveryRequest == null || !mDiscoveryRequest.equals(request))) {
54911417b1cfde8f1749905f2d735623af9214148afJeff Brown                mDiscoveryRequest = request;
55011417b1cfde8f1749905f2d735623af9214148afJeff Brown                return updateCompositeDiscoveryRequest();
55128520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown            }
55228520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown            return false;
55328520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown        }
55428520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown
55528520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown        // Runs on a binder thread.
556fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        @Override
557fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        public void binderDied() {
558fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            mPrivateHandler.obtainMessage(PRIVATE_MSG_CLIENT_DIED, mMessenger).sendToTarget();
559fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        }
560fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
561fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        @Override
562fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        public String toString() {
563fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            return getClientId(mMessenger);
564fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        }
565fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    }
566fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
567fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    /**
568fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown     * Handler that receives messages from clients.
569fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown     * <p>
570fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown     * This inner class is static and only retains a weak reference to the service
571fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown     * to prevent the service from being leaked in case one of the clients is holding an
572fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown     * active reference to the server's messenger.
573fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown     * </p><p>
574fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown     * This handler should not be used to handle any messages other than those
575fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown     * that come from the client.
576fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown     * </p>
577fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown     */
578fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    private static final class ReceiveHandler extends Handler {
579fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        private final WeakReference<MediaRouteProviderService> mServiceRef;
580fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
581fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        public ReceiveHandler(MediaRouteProviderService service) {
582fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            mServiceRef = new WeakReference<MediaRouteProviderService>(service);
583fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        }
584fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
585fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        @Override
586fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        public void handleMessage(Message msg) {
587fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            final Messenger messenger = msg.replyTo;
588fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            if (isValidRemoteMessenger(messenger)) {
589fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                final int what = msg.what;
590fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                final int requestId = msg.arg1;
591fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                final int arg = msg.arg2;
592fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                final Object obj = msg.obj;
593fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                final Bundle data = msg.peekData();
594fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                if (!processMessage(what, messenger, requestId, arg, obj, data)) {
595fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    if (DEBUG) {
596fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                        Log.d(TAG, getClientId(messenger) + ": Message failed, what=" + what
597fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                                + ", requestId=" + requestId + ", arg=" + arg
598fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                                + ", obj=" + obj + ", data=" + data);
599fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    }
600fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    sendGenericFailure(messenger, requestId);
601fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                }
602fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            } else {
603fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                if (DEBUG) {
604fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    Log.d(TAG, "Ignoring message without valid reply messenger.");
605fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                }
606fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            }
607fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        }
608fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
609fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        private boolean processMessage(int what,
610fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                Messenger messenger, int requestId, int arg, Object obj, Bundle data) {
611fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            MediaRouteProviderService service = mServiceRef.get();
612fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            if (service != null) {
613fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                switch (what) {
614fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    case CLIENT_MSG_REGISTER:
615fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                        return service.onRegisterClient(messenger, requestId, arg);
616fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
617fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    case CLIENT_MSG_UNREGISTER:
618fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                        return service.onUnregisterClient(messenger, requestId);
619fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
620fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    case CLIENT_MSG_CREATE_ROUTE_CONTROLLER: {
621fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                        String routeId = data.getString(CLIENT_DATA_ROUTE_ID);
622fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                        if (routeId != null) {
623fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                            return service.onCreateRouteController(
624fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                                    messenger, requestId, arg, routeId);
625fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                        }
626fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                        break;
627fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    }
628fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
629fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    case CLIENT_MSG_RELEASE_ROUTE_CONTROLLER:
630fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                        return service.onReleaseRouteController(messenger, requestId, arg);
631fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
632fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    case CLIENT_MSG_SELECT_ROUTE:
633fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                        return service.onSelectRoute(messenger, requestId, arg);
634fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
635fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    case CLIENT_MSG_UNSELECT_ROUTE:
63694be6100218126ce6a08bf1f56209578500b361fRoboErik                        int reason = data == null ?
63794be6100218126ce6a08bf1f56209578500b361fRoboErik                                MediaRouter.UNSELECT_REASON_UNKNOWN
63894be6100218126ce6a08bf1f56209578500b361fRoboErik                                : data.getInt(CLIENT_DATA_UNSELECT_REASON,
63994be6100218126ce6a08bf1f56209578500b361fRoboErik                                        MediaRouter.UNSELECT_REASON_UNKNOWN);
64094be6100218126ce6a08bf1f56209578500b361fRoboErik                        return service.onUnselectRoute(messenger, requestId, arg, reason);
641fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
642fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    case CLIENT_MSG_SET_ROUTE_VOLUME: {
643fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                        int volume = data.getInt(CLIENT_DATA_VOLUME, -1);
644fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                        if (volume >= 0) {
645fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                            return service.onSetRouteVolume(
646fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                                    messenger, requestId, arg, volume);
647fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                        }
648fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                        break;
649fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    }
650fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
651fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    case CLIENT_MSG_UPDATE_ROUTE_VOLUME: {
652fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                        int delta = data.getInt(CLIENT_DATA_VOLUME, 0);
653fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                        if (delta != 0) {
654fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                            return service.onUpdateRouteVolume(
655fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                                    messenger, requestId, arg, delta);
656fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                        }
657fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                        break;
658fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    }
659fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
660fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    case CLIENT_MSG_ROUTE_CONTROL_REQUEST:
661fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                        if (obj instanceof Intent) {
662fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                            return service.onRouteControlRequest(
663fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                                    messenger, requestId, arg, (Intent)obj);
664fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                        }
665fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                        break;
66628520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown
66711417b1cfde8f1749905f2d735623af9214148afJeff Brown                    case CLIENT_MSG_SET_DISCOVERY_REQUEST: {
668f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown                        if (obj == null || obj instanceof Bundle) {
66911417b1cfde8f1749905f2d735623af9214148afJeff Brown                            MediaRouteDiscoveryRequest request =
67011417b1cfde8f1749905f2d735623af9214148afJeff Brown                                    MediaRouteDiscoveryRequest.fromBundle((Bundle)obj);
67111417b1cfde8f1749905f2d735623af9214148afJeff Brown                            return service.onSetDiscoveryRequest(
672f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown                                    messenger, requestId,
673f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown                                    request != null && request.isValid() ? request : null);
67411417b1cfde8f1749905f2d735623af9214148afJeff Brown                        }
67511417b1cfde8f1749905f2d735623af9214148afJeff Brown                    }
676fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                }
677fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            }
678fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            return false;
679fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        }
680fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    }
681fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown}
682