1 /*
2  * Copyright (C) 2013 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.support.v7.media;
18 
19 import android.app.Service;
20 import android.content.Intent;
21 import android.os.Handler;
22 import android.os.IBinder;
23 import android.os.IBinder.DeathRecipient;
24 import android.os.Bundle;
25 import android.os.DeadObjectException;
26 import android.os.Message;
27 import android.os.Messenger;
28 import android.os.RemoteException;
29 import android.util.Log;
30 import android.util.SparseArray;
31 
32 import java.lang.ref.WeakReference;
33 import java.util.ArrayList;
34 
35 import static android.support.v7.media.MediaRouteProviderProtocol.*;
36 
37 /**
38  * Base class for media route provider services.
39  * <p>
40  * To implement your own media route provider service, extend this class and
41  * override the {@link #onCreateMediaRouteProvider} method to return an
42  * instance of your {@link MediaRouteProvider}.
43  * </p><p>
44  * Declare your media route provider service in your application manifest
45  * like this:
46  * </p>
47  * <pre>
48  *   &lt;service android:name=".MyMediaRouteProviderService"
49  *           android:label="@string/my_media_route_provider_service">
50  *       &lt;intent-filter>
51  *           &lt;action android:name="android.media.MediaRouteProviderService" />
52  *       &lt;/intent-filter>
53  *   &lt;/service>
54  * </pre>
55  */
56 public abstract class MediaRouteProviderService extends Service {
57     private static final String TAG = "MediaRouteProviderSrv"; // max. 23 chars
58     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
59 
60     private final ArrayList<ClientRecord> mClients = new ArrayList<ClientRecord>();
61     private final ReceiveHandler mReceiveHandler;
62     private final Messenger mReceiveMessenger;
63     private final PrivateHandler mPrivateHandler;
64     private final ProviderCallback mProviderCallback;
65 
66     private MediaRouteProvider mProvider;
67     private MediaRouteDiscoveryRequest mCompositeDiscoveryRequest;
68 
69     /**
70      * The {@link Intent} that must be declared as handled by the service.
71      * Put this in your manifest.
72      */
73     public static final String SERVICE_INTERFACE = MediaRouteProviderProtocol.SERVICE_INTERFACE;
74 
75     /*
76      * Private messages used internally.  (Yes, you can renumber these.)
77      */
78 
79     private static final int PRIVATE_MSG_CLIENT_DIED = 1;
80 
81     /**
82      * Creates a media route provider service.
83      */
MediaRouteProviderService()84     public MediaRouteProviderService() {
85         mReceiveHandler = new ReceiveHandler(this);
86         mReceiveMessenger = new Messenger(mReceiveHandler);
87         mPrivateHandler = new PrivateHandler();
88         mProviderCallback = new ProviderCallback();
89     }
90 
91     /**
92      * Called by the system when it is time to create the media route provider.
93      *
94      * @return The media route provider offered by this service, or null if
95      * this service has decided not to offer a media route provider.
96      */
onCreateMediaRouteProvider()97     public abstract MediaRouteProvider onCreateMediaRouteProvider();
98 
99     /**
100      * Gets the media route provider offered by this service.
101      *
102      * @return The media route provider offered by this service, or null if
103      * it has not yet been created.
104      *
105      * @see #onCreateMediaRouteProvider()
106      */
getMediaRouteProvider()107     public MediaRouteProvider getMediaRouteProvider() {
108         return mProvider;
109     }
110 
111     @Override
onBind(Intent intent)112     public IBinder onBind(Intent intent) {
113         if (intent.getAction().equals(SERVICE_INTERFACE)) {
114             if (mProvider == null) {
115                 MediaRouteProvider provider = onCreateMediaRouteProvider();
116                 if (provider != null) {
117                     String providerPackage = provider.getMetadata().getPackageName();
118                     if (!providerPackage.equals(getPackageName())) {
119                         throw new IllegalStateException("onCreateMediaRouteProvider() returned "
120                                 + "a provider whose package name does not match the package "
121                                 + "name of the service.  A media route provider service can "
122                                 + "only export its own media route providers.  "
123                                 + "Provider package name: " + providerPackage
124                                 + ".  Service package name: " + getPackageName() + ".");
125                     }
126                     mProvider = provider;
127                     mProvider.setCallback(mProviderCallback);
128                 }
129             }
130             if (mProvider != null) {
131                 return mReceiveMessenger.getBinder();
132             }
133         }
134         return null;
135     }
136 
onRegisterClient(Messenger messenger, int requestId, int version)137     private boolean onRegisterClient(Messenger messenger, int requestId, int version) {
138         if (version >= CLIENT_VERSION_1) {
139             int index = findClient(messenger);
140             if (index < 0) {
141                 ClientRecord client = new ClientRecord(messenger, version);
142                 if (client.register()) {
143                     mClients.add(client);
144                     if (DEBUG) {
145                         Log.d(TAG, client + ": Registered, version=" + version);
146                     }
147                     if (requestId != 0) {
148                         MediaRouteProviderDescriptor descriptor = mProvider.getDescriptor();
149                         sendReply(messenger, SERVICE_MSG_REGISTERED,
150                                 requestId, SERVICE_VERSION_CURRENT,
151                                 descriptor != null ? descriptor.asBundle() : null, null);
152                     }
153                     return true;
154                 }
155             }
156         }
157         return false;
158     }
159 
onUnregisterClient(Messenger messenger, int requestId)160     private boolean onUnregisterClient(Messenger messenger, int requestId) {
161         int index = findClient(messenger);
162         if (index >= 0) {
163             ClientRecord client = mClients.remove(index);
164             if (DEBUG) {
165                 Log.d(TAG, client + ": Unregistered");
166             }
167             client.dispose();
168             sendGenericSuccess(messenger, requestId);
169             return true;
170         }
171         return false;
172     }
173 
onBinderDied(Messenger messenger)174     private void onBinderDied(Messenger messenger) {
175         int index = findClient(messenger);
176         if (index >= 0) {
177             ClientRecord client = mClients.remove(index);
178             if (DEBUG) {
179                 Log.d(TAG, client + ": Binder died");
180             }
181             client.dispose();
182         }
183     }
184 
onCreateRouteController(Messenger messenger, int requestId, int controllerId, String routeId)185     private boolean onCreateRouteController(Messenger messenger, int requestId,
186             int controllerId, String routeId) {
187         ClientRecord client = getClient(messenger);
188         if (client != null) {
189             if (client.createRouteController(routeId, controllerId)) {
190                 if (DEBUG) {
191                     Log.d(TAG, client + ": Route controller created"
192                             + ", controllerId=" + controllerId + ", routeId=" + routeId);
193                 }
194                 sendGenericSuccess(messenger, requestId);
195                 return true;
196             }
197         }
198         return false;
199     }
200 
onReleaseRouteController(Messenger messenger, int requestId, int controllerId)201     private boolean onReleaseRouteController(Messenger messenger, int requestId,
202             int controllerId) {
203         ClientRecord client = getClient(messenger);
204         if (client != null) {
205             if (client.releaseRouteController(controllerId)) {
206                 if (DEBUG) {
207                     Log.d(TAG, client + ": Route controller released"
208                             + ", controllerId=" + controllerId);
209                 }
210                 sendGenericSuccess(messenger, requestId);
211                 return true;
212             }
213         }
214         return false;
215     }
216 
onSelectRoute(Messenger messenger, int requestId, int controllerId)217     private boolean onSelectRoute(Messenger messenger, int requestId,
218             int controllerId) {
219         ClientRecord client = getClient(messenger);
220         if (client != null) {
221             MediaRouteProvider.RouteController controller =
222                     client.getRouteController(controllerId);
223             if (controller != null) {
224                 controller.onSelect();
225                 if (DEBUG) {
226                     Log.d(TAG, client + ": Route selected"
227                             + ", controllerId=" + controllerId);
228                 }
229                 sendGenericSuccess(messenger, requestId);
230                 return true;
231             }
232         }
233         return false;
234     }
235 
onUnselectRoute(Messenger messenger, int requestId, int controllerId, int reason)236     private boolean onUnselectRoute(Messenger messenger, int requestId,
237             int controllerId, int reason) {
238         ClientRecord client = getClient(messenger);
239         if (client != null) {
240             MediaRouteProvider.RouteController controller =
241                     client.getRouteController(controllerId);
242             if (controller != null) {
243                 controller.onUnselect(reason);
244                 if (DEBUG) {
245                     Log.d(TAG, client + ": Route unselected"
246                             + ", controllerId=" + controllerId);
247                 }
248                 sendGenericSuccess(messenger, requestId);
249                 return true;
250             }
251         }
252         return false;
253     }
254 
onSetRouteVolume(Messenger messenger, int requestId, int controllerId, int volume)255     private boolean onSetRouteVolume(Messenger messenger, int requestId,
256             int controllerId, int volume) {
257         ClientRecord client = getClient(messenger);
258         if (client != null) {
259             MediaRouteProvider.RouteController controller =
260                     client.getRouteController(controllerId);
261             if (controller != null) {
262                 controller.onSetVolume(volume);
263                 if (DEBUG) {
264                     Log.d(TAG, client + ": Route volume changed"
265                             + ", controllerId=" + controllerId + ", volume=" + volume);
266                 }
267                 sendGenericSuccess(messenger, requestId);
268                 return true;
269             }
270         }
271         return false;
272     }
273 
onUpdateRouteVolume(Messenger messenger, int requestId, int controllerId, int delta)274     private boolean onUpdateRouteVolume(Messenger messenger, int requestId,
275             int controllerId, int delta) {
276         ClientRecord client = getClient(messenger);
277         if (client != null) {
278             MediaRouteProvider.RouteController controller =
279                     client.getRouteController(controllerId);
280             if (controller != null) {
281                 controller.onUpdateVolume(delta);
282                 if (DEBUG) {
283                     Log.d(TAG, client + ": Route volume updated"
284                             + ", controllerId=" + controllerId + ", delta=" + delta);
285                 }
286                 sendGenericSuccess(messenger, requestId);
287                 return true;
288             }
289         }
290         return false;
291     }
292 
onRouteControlRequest(final Messenger messenger, final int requestId, final int controllerId, final Intent intent)293     private boolean onRouteControlRequest(final Messenger messenger, final int requestId,
294             final int controllerId, final Intent intent) {
295         final ClientRecord client = getClient(messenger);
296         if (client != null) {
297             MediaRouteProvider.RouteController controller =
298                     client.getRouteController(controllerId);
299             if (controller != null) {
300                 MediaRouter.ControlRequestCallback callback = null;
301                 if (requestId != 0) {
302                     callback = new MediaRouter.ControlRequestCallback() {
303                         @Override
304                         public void onResult(Bundle data) {
305                             if (DEBUG) {
306                                 Log.d(TAG, client + ": Route control request succeeded"
307                                         + ", controllerId=" + controllerId
308                                         + ", intent=" + intent
309                                         + ", data=" + data);
310                             }
311                             if (findClient(messenger) >= 0) {
312                                 sendReply(messenger, SERVICE_MSG_CONTROL_REQUEST_SUCCEEDED,
313                                         requestId, 0, data, null);
314                             }
315                         }
316 
317                         @Override
318                         public void onError(String error, Bundle data) {
319                             if (DEBUG) {
320                                 Log.d(TAG, client + ": Route control request failed"
321                                         + ", controllerId=" + controllerId
322                                         + ", intent=" + intent
323                                         + ", error=" + error + ", data=" + data);
324                             }
325                             if (findClient(messenger) >= 0) {
326                                 if (error != null) {
327                                     Bundle bundle = new Bundle();
328                                     bundle.putString(SERVICE_DATA_ERROR, error);
329                                     sendReply(messenger, SERVICE_MSG_CONTROL_REQUEST_FAILED,
330                                             requestId, 0, data, bundle);
331                                 } else {
332                                     sendReply(messenger, SERVICE_MSG_CONTROL_REQUEST_FAILED,
333                                             requestId, 0, data, null);
334                                 }
335                             }
336                         }
337                     };
338                 }
339                 if (controller.onControlRequest(intent, callback)) {
340                     if (DEBUG) {
341                         Log.d(TAG, client + ": Route control request delivered"
342                                 + ", controllerId=" + controllerId + ", intent=" + intent);
343                     }
344                     return true;
345                 }
346             }
347         }
348         return false;
349     }
350 
onSetDiscoveryRequest(Messenger messenger, int requestId, MediaRouteDiscoveryRequest request)351     private boolean onSetDiscoveryRequest(Messenger messenger, int requestId,
352             MediaRouteDiscoveryRequest request) {
353         ClientRecord client = getClient(messenger);
354         if (client != null) {
355             boolean actuallyChanged = client.setDiscoveryRequest(request);
356             if (DEBUG) {
357                 Log.d(TAG, client + ": Set discovery request, request=" + request
358                         + ", actuallyChanged=" + actuallyChanged
359                         + ", compositeDiscoveryRequest=" + mCompositeDiscoveryRequest);
360             }
361             sendGenericSuccess(messenger, requestId);
362             return true;
363         }
364         return false;
365     }
366 
sendDescriptorChanged(MediaRouteProviderDescriptor descriptor)367     private void sendDescriptorChanged(MediaRouteProviderDescriptor descriptor) {
368         Bundle descriptorBundle = descriptor != null ? descriptor.asBundle() : null;
369         final int count = mClients.size();
370         for (int i = 0; i < count; i++) {
371             ClientRecord client = mClients.get(i);
372             sendReply(client.mMessenger, SERVICE_MSG_DESCRIPTOR_CHANGED, 0, 0,
373                     descriptorBundle, null);
374             if (DEBUG) {
375                 Log.d(TAG, client + ": Sent descriptor change event, descriptor=" + descriptor);
376             }
377         }
378     }
379 
updateCompositeDiscoveryRequest()380     private boolean updateCompositeDiscoveryRequest() {
381         MediaRouteDiscoveryRequest composite = null;
382         MediaRouteSelector.Builder selectorBuilder = null;
383         boolean activeScan = false;
384         final int count = mClients.size();
385         for (int i = 0; i < count; i++) {
386             MediaRouteDiscoveryRequest request = mClients.get(i).mDiscoveryRequest;
387             if (request != null
388                     && (!request.getSelector().isEmpty() || request.isActiveScan())) {
389                 activeScan |= request.isActiveScan();
390                 if (composite == null) {
391                     composite = request;
392                 } else {
393                     if (selectorBuilder == null) {
394                         selectorBuilder = new MediaRouteSelector.Builder(composite.getSelector());
395                     }
396                     selectorBuilder.addSelector(request.getSelector());
397                 }
398             }
399         }
400         if (selectorBuilder != null) {
401             composite = new MediaRouteDiscoveryRequest(selectorBuilder.build(), activeScan);
402         }
403         if (mCompositeDiscoveryRequest != composite
404                 && (mCompositeDiscoveryRequest == null
405                         || !mCompositeDiscoveryRequest.equals(composite))) {
406             mCompositeDiscoveryRequest = composite;
407             mProvider.setDiscoveryRequest(composite);
408             return true;
409         }
410         return false;
411     }
412 
getClient(Messenger messenger)413     private ClientRecord getClient(Messenger messenger) {
414         int index = findClient(messenger);
415         return index >= 0 ? mClients.get(index) : null;
416     }
417 
findClient(Messenger messenger)418     private int findClient(Messenger messenger) {
419         final int count = mClients.size();
420         for (int i = 0; i < count; i++) {
421             ClientRecord client = mClients.get(i);
422             if (client.hasMessenger(messenger)) {
423                 return i;
424             }
425         }
426         return -1;
427     }
428 
sendGenericFailure(Messenger messenger, int requestId)429     private static void sendGenericFailure(Messenger messenger, int requestId) {
430         if (requestId != 0) {
431             sendReply(messenger, SERVICE_MSG_GENERIC_FAILURE, requestId, 0, null, null);
432         }
433     }
434 
sendGenericSuccess(Messenger messenger, int requestId)435     private static void sendGenericSuccess(Messenger messenger, int requestId) {
436         if (requestId != 0) {
437             sendReply(messenger, SERVICE_MSG_GENERIC_SUCCESS, requestId, 0, null, null);
438         }
439     }
440 
sendReply(Messenger messenger, int what, int requestId, int arg, Object obj, Bundle data)441     private static void sendReply(Messenger messenger, int what,
442             int requestId, int arg, Object obj, Bundle data) {
443         Message msg = Message.obtain();
444         msg.what = what;
445         msg.arg1 = requestId;
446         msg.arg2 = arg;
447         msg.obj = obj;
448         msg.setData(data);
449         try {
450             messenger.send(msg);
451         } catch (DeadObjectException ex) {
452             // The client died.
453         } catch (RemoteException ex) {
454             Log.e(TAG, "Could not send message to " + getClientId(messenger), ex);
455         }
456     }
457 
getClientId(Messenger messenger)458     private static String getClientId(Messenger messenger) {
459         return "Client connection " + messenger.getBinder().toString();
460     }
461 
462     private final class PrivateHandler extends Handler {
463         @Override
handleMessage(Message msg)464         public void handleMessage(Message msg) {
465             switch (msg.what) {
466                 case PRIVATE_MSG_CLIENT_DIED:
467                     onBinderDied((Messenger)msg.obj);
468                     break;
469             }
470         }
471     }
472 
473     private final class ProviderCallback extends MediaRouteProvider.Callback {
474         @Override
onDescriptorChanged(MediaRouteProvider provider, MediaRouteProviderDescriptor descriptor)475         public void onDescriptorChanged(MediaRouteProvider provider,
476                 MediaRouteProviderDescriptor descriptor) {
477             sendDescriptorChanged(descriptor);
478         }
479     }
480 
481     private final class ClientRecord implements DeathRecipient {
482         public final Messenger mMessenger;
483         public final int mVersion;
484         public MediaRouteDiscoveryRequest mDiscoveryRequest;
485 
486         private final SparseArray<MediaRouteProvider.RouteController> mControllers =
487                 new SparseArray<MediaRouteProvider.RouteController>();
488 
ClientRecord(Messenger messenger, int version)489         public ClientRecord(Messenger messenger, int version) {
490             mMessenger = messenger;
491             mVersion = version;
492         }
493 
register()494         public boolean register() {
495             try {
496                 mMessenger.getBinder().linkToDeath(this, 0);
497                 return true;
498             } catch (RemoteException ex) {
499                 binderDied();
500             }
501             return false;
502         }
503 
dispose()504         public void dispose() {
505             int count = mControllers.size();
506             for (int i = 0; i < count; i++) {
507                 mControllers.valueAt(i).onRelease();
508             }
509             mControllers.clear();
510 
511             mMessenger.getBinder().unlinkToDeath(this, 0);
512 
513             setDiscoveryRequest(null);
514         }
515 
hasMessenger(Messenger other)516         public boolean hasMessenger(Messenger other) {
517             return mMessenger.getBinder() == other.getBinder();
518         }
519 
createRouteController(String routeId, int controllerId)520         public boolean createRouteController(String routeId, int controllerId) {
521             if (mControllers.indexOfKey(controllerId) < 0) {
522                 MediaRouteProvider.RouteController controller =
523                         mProvider.onCreateRouteController(routeId);
524                 if (controller != null) {
525                     mControllers.put(controllerId, controller);
526                     return true;
527                 }
528             }
529             return false;
530         }
531 
releaseRouteController(int controllerId)532         public boolean releaseRouteController(int controllerId) {
533             MediaRouteProvider.RouteController controller = mControllers.get(controllerId);
534             if (controller != null) {
535                 mControllers.remove(controllerId);
536                 controller.onRelease();
537                 return true;
538             }
539             return false;
540         }
541 
getRouteController(int controllerId)542         public MediaRouteProvider.RouteController getRouteController(int controllerId) {
543             return mControllers.get(controllerId);
544         }
545 
setDiscoveryRequest(MediaRouteDiscoveryRequest request)546         public boolean setDiscoveryRequest(MediaRouteDiscoveryRequest request) {
547             if (mDiscoveryRequest != request
548                     && (mDiscoveryRequest == null || !mDiscoveryRequest.equals(request))) {
549                 mDiscoveryRequest = request;
550                 return updateCompositeDiscoveryRequest();
551             }
552             return false;
553         }
554 
555         // Runs on a binder thread.
556         @Override
binderDied()557         public void binderDied() {
558             mPrivateHandler.obtainMessage(PRIVATE_MSG_CLIENT_DIED, mMessenger).sendToTarget();
559         }
560 
561         @Override
toString()562         public String toString() {
563             return getClientId(mMessenger);
564         }
565     }
566 
567     /**
568      * Handler that receives messages from clients.
569      * <p>
570      * This inner class is static and only retains a weak reference to the service
571      * to prevent the service from being leaked in case one of the clients is holding an
572      * active reference to the server's messenger.
573      * </p><p>
574      * This handler should not be used to handle any messages other than those
575      * that come from the client.
576      * </p>
577      */
578     private static final class ReceiveHandler extends Handler {
579         private final WeakReference<MediaRouteProviderService> mServiceRef;
580 
ReceiveHandler(MediaRouteProviderService service)581         public ReceiveHandler(MediaRouteProviderService service) {
582             mServiceRef = new WeakReference<MediaRouteProviderService>(service);
583         }
584 
585         @Override
handleMessage(Message msg)586         public void handleMessage(Message msg) {
587             final Messenger messenger = msg.replyTo;
588             if (isValidRemoteMessenger(messenger)) {
589                 final int what = msg.what;
590                 final int requestId = msg.arg1;
591                 final int arg = msg.arg2;
592                 final Object obj = msg.obj;
593                 final Bundle data = msg.peekData();
594                 if (!processMessage(what, messenger, requestId, arg, obj, data)) {
595                     if (DEBUG) {
596                         Log.d(TAG, getClientId(messenger) + ": Message failed, what=" + what
597                                 + ", requestId=" + requestId + ", arg=" + arg
598                                 + ", obj=" + obj + ", data=" + data);
599                     }
600                     sendGenericFailure(messenger, requestId);
601                 }
602             } else {
603                 if (DEBUG) {
604                     Log.d(TAG, "Ignoring message without valid reply messenger.");
605                 }
606             }
607         }
608 
processMessage(int what, Messenger messenger, int requestId, int arg, Object obj, Bundle data)609         private boolean processMessage(int what,
610                 Messenger messenger, int requestId, int arg, Object obj, Bundle data) {
611             MediaRouteProviderService service = mServiceRef.get();
612             if (service != null) {
613                 switch (what) {
614                     case CLIENT_MSG_REGISTER:
615                         return service.onRegisterClient(messenger, requestId, arg);
616 
617                     case CLIENT_MSG_UNREGISTER:
618                         return service.onUnregisterClient(messenger, requestId);
619 
620                     case CLIENT_MSG_CREATE_ROUTE_CONTROLLER: {
621                         String routeId = data.getString(CLIENT_DATA_ROUTE_ID);
622                         if (routeId != null) {
623                             return service.onCreateRouteController(
624                                     messenger, requestId, arg, routeId);
625                         }
626                         break;
627                     }
628 
629                     case CLIENT_MSG_RELEASE_ROUTE_CONTROLLER:
630                         return service.onReleaseRouteController(messenger, requestId, arg);
631 
632                     case CLIENT_MSG_SELECT_ROUTE:
633                         return service.onSelectRoute(messenger, requestId, arg);
634 
635                     case CLIENT_MSG_UNSELECT_ROUTE:
636                         int reason = data == null ?
637                                 MediaRouter.UNSELECT_REASON_UNKNOWN
638                                 : data.getInt(CLIENT_DATA_UNSELECT_REASON,
639                                         MediaRouter.UNSELECT_REASON_UNKNOWN);
640                         return service.onUnselectRoute(messenger, requestId, arg, reason);
641 
642                     case CLIENT_MSG_SET_ROUTE_VOLUME: {
643                         int volume = data.getInt(CLIENT_DATA_VOLUME, -1);
644                         if (volume >= 0) {
645                             return service.onSetRouteVolume(
646                                     messenger, requestId, arg, volume);
647                         }
648                         break;
649                     }
650 
651                     case CLIENT_MSG_UPDATE_ROUTE_VOLUME: {
652                         int delta = data.getInt(CLIENT_DATA_VOLUME, 0);
653                         if (delta != 0) {
654                             return service.onUpdateRouteVolume(
655                                     messenger, requestId, arg, delta);
656                         }
657                         break;
658                     }
659 
660                     case CLIENT_MSG_ROUTE_CONTROL_REQUEST:
661                         if (obj instanceof Intent) {
662                             return service.onRouteControlRequest(
663                                     messenger, requestId, arg, (Intent)obj);
664                         }
665                         break;
666 
667                     case CLIENT_MSG_SET_DISCOVERY_REQUEST: {
668                         if (obj == null || obj instanceof Bundle) {
669                             MediaRouteDiscoveryRequest request =
670                                     MediaRouteDiscoveryRequest.fromBundle((Bundle)obj);
671                             return service.onSetDiscoveryRequest(
672                                     messenger, requestId,
673                                     request != null && request.isValid() ? request : null);
674                         }
675                     }
676                 }
677             }
678             return false;
679         }
680     }
681 }
682