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 * <service android:name=".MyMediaRouteProviderService" 95 * android:label="@string/my_media_route_provider_service"> 96 * <intent-filter> 97 * <action android:name="android.media.MediaRouteProviderService" /> 98 * </intent-filter> 99 * </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