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