MediaControllerCompat.java revision 203a34227e8fa3bd16721fb7ff450fb6feba7c50
1/* 2 * Copyright (C) 2014 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 17package android.support.v4.media.session; 18 19import android.app.PendingIntent; 20import android.content.Context; 21import android.media.AudioManager; 22import android.net.Uri; 23import android.os.Bundle; 24import android.os.Handler; 25import android.os.IBinder; 26import android.os.Looper; 27import android.os.Message; 28import android.os.RemoteException; 29import android.os.ResultReceiver; 30import android.support.v4.media.MediaMetadataCompat; 31import android.support.v4.media.RatingCompat; 32import android.support.v4.media.VolumeProviderCompat; 33import android.support.v4.media.session.MediaSessionCompat.QueueItem; 34import android.support.v4.media.session.PlaybackStateCompat.CustomAction; 35import android.text.TextUtils; 36import android.util.Log; 37import android.view.KeyEvent; 38 39import java.util.List; 40 41/** 42 * Allows an app to interact with an ongoing media session. Media buttons and 43 * other commands can be sent to the session. A callback may be registered to 44 * receive updates from the session, such as metadata and play state changes. 45 * <p> 46 * A MediaController can be created if you have a {@link MediaSessionCompat.Token} 47 * from the session owner. 48 * <p> 49 * MediaController objects are thread-safe. 50 * <p> 51 * This is a helper for accessing features in {@link android.media.session.MediaSession} 52 * introduced after API level 4 in a backwards compatible fashion. 53 */ 54public final class MediaControllerCompat { 55 private static final String TAG = "MediaControllerCompat"; 56 57 private final MediaControllerImpl mImpl; 58 private final MediaSessionCompat.Token mToken; 59 60 /** 61 * Creates a media controller from a session. 62 * 63 * @param session The session to be controlled. 64 */ 65 public MediaControllerCompat(Context context, MediaSessionCompat session) { 66 if (session == null) { 67 throw new IllegalArgumentException("session must not be null"); 68 } 69 mToken = session.getSessionToken(); 70 71 if (android.os.Build.VERSION.SDK_INT >= 24) { 72 mImpl = new MediaControllerImplApi24(context, session); 73 } else if (android.os.Build.VERSION.SDK_INT >= 23) { 74 mImpl = new MediaControllerImplApi23(context, session); 75 } else if (android.os.Build.VERSION.SDK_INT >= 21) { 76 mImpl = new MediaControllerImplApi21(context, session); 77 } else { 78 mImpl = new MediaControllerImplBase(mToken); 79 } 80 } 81 82 /** 83 * Creates a media controller from a session token which may have 84 * been obtained from another process. 85 * 86 * @param sessionToken The token of the session to be controlled. 87 * @throws RemoteException if the session is not accessible. 88 */ 89 public MediaControllerCompat(Context context, MediaSessionCompat.Token sessionToken) 90 throws RemoteException { 91 if (sessionToken == null) { 92 throw new IllegalArgumentException("sessionToken must not be null"); 93 } 94 mToken = sessionToken; 95 96 if (android.os.Build.VERSION.SDK_INT >= 24) { 97 mImpl = new MediaControllerImplApi24(context, sessionToken); 98 } else if (android.os.Build.VERSION.SDK_INT >= 23) { 99 mImpl = new MediaControllerImplApi23(context, sessionToken); 100 } else if (android.os.Build.VERSION.SDK_INT >= 21) { 101 mImpl = new MediaControllerImplApi21(context, sessionToken); 102 } else { 103 mImpl = new MediaControllerImplBase(mToken); 104 } 105 } 106 107 /** 108 * Get a {@link TransportControls} instance for this session. 109 * 110 * @return A controls instance 111 */ 112 public TransportControls getTransportControls() { 113 return mImpl.getTransportControls(); 114 } 115 116 /** 117 * Send the specified media button event to the session. Only media keys can 118 * be sent by this method, other keys will be ignored. 119 * 120 * @param keyEvent The media button event to dispatch. 121 * @return true if the event was sent to the session, false otherwise. 122 */ 123 public boolean dispatchMediaButtonEvent(KeyEvent keyEvent) { 124 if (keyEvent == null) { 125 throw new IllegalArgumentException("KeyEvent may not be null"); 126 } 127 return mImpl.dispatchMediaButtonEvent(keyEvent); 128 } 129 130 /** 131 * Get the current playback state for this session. 132 * 133 * @return The current PlaybackState or null 134 */ 135 public PlaybackStateCompat getPlaybackState() { 136 return mImpl.getPlaybackState(); 137 } 138 139 /** 140 * Get the current metadata for this session. 141 * 142 * @return The current MediaMetadata or null. 143 */ 144 public MediaMetadataCompat getMetadata() { 145 return mImpl.getMetadata(); 146 } 147 148 /** 149 * Get the current play queue for this session if one is set. If you only 150 * care about the current item {@link #getMetadata()} should be used. 151 * 152 * @return The current play queue or null. 153 */ 154 public List<MediaSessionCompat.QueueItem> getQueue() { 155 return mImpl.getQueue(); 156 } 157 158 /** 159 * Get the queue title for this session. 160 */ 161 public CharSequence getQueueTitle() { 162 return mImpl.getQueueTitle(); 163 } 164 165 /** 166 * Get the extras for this session. 167 */ 168 public Bundle getExtras() { 169 return mImpl.getExtras(); 170 } 171 172 /** 173 * Get the rating type supported by the session. One of: 174 * <ul> 175 * <li>{@link RatingCompat#RATING_NONE}</li> 176 * <li>{@link RatingCompat#RATING_HEART}</li> 177 * <li>{@link RatingCompat#RATING_THUMB_UP_DOWN}</li> 178 * <li>{@link RatingCompat#RATING_3_STARS}</li> 179 * <li>{@link RatingCompat#RATING_4_STARS}</li> 180 * <li>{@link RatingCompat#RATING_5_STARS}</li> 181 * <li>{@link RatingCompat#RATING_PERCENTAGE}</li> 182 * </ul> 183 * 184 * @return The supported rating type 185 */ 186 public int getRatingType() { 187 return mImpl.getRatingType(); 188 } 189 190 /** 191 * Get the flags for this session. Flags are defined in 192 * {@link MediaSessionCompat}. 193 * 194 * @return The current set of flags for the session. 195 */ 196 public long getFlags() { 197 return mImpl.getFlags(); 198 } 199 200 /** 201 * Get the current playback info for this session. 202 * 203 * @return The current playback info or null. 204 */ 205 public PlaybackInfo getPlaybackInfo() { 206 return mImpl.getPlaybackInfo(); 207 } 208 209 /** 210 * Get an intent for launching UI associated with this session if one 211 * exists. 212 * 213 * @return A {@link PendingIntent} to launch UI or null. 214 */ 215 public PendingIntent getSessionActivity() { 216 return mImpl.getSessionActivity(); 217 } 218 219 /** 220 * Get the token for the session this controller is connected to. 221 * 222 * @return The session's token. 223 */ 224 public MediaSessionCompat.Token getSessionToken() { 225 return mToken; 226 } 227 228 /** 229 * Set the volume of the output this session is playing on. The command will 230 * be ignored if it does not support 231 * {@link VolumeProviderCompat#VOLUME_CONTROL_ABSOLUTE}. The flags in 232 * {@link AudioManager} may be used to affect the handling. 233 * 234 * @see #getPlaybackInfo() 235 * @param value The value to set it to, between 0 and the reported max. 236 * @param flags Flags from {@link AudioManager} to include with the volume 237 * request. 238 */ 239 public void setVolumeTo(int value, int flags) { 240 mImpl.setVolumeTo(value, flags); 241 } 242 243 /** 244 * Adjust the volume of the output this session is playing on. The direction 245 * must be one of {@link AudioManager#ADJUST_LOWER}, 246 * {@link AudioManager#ADJUST_RAISE}, or {@link AudioManager#ADJUST_SAME}. 247 * The command will be ignored if the session does not support 248 * {@link VolumeProviderCompat#VOLUME_CONTROL_RELATIVE} or 249 * {@link VolumeProviderCompat#VOLUME_CONTROL_ABSOLUTE}. The flags in 250 * {@link AudioManager} may be used to affect the handling. 251 * 252 * @see #getPlaybackInfo() 253 * @param direction The direction to adjust the volume in. 254 * @param flags Any flags to pass with the command. 255 */ 256 public void adjustVolume(int direction, int flags) { 257 mImpl.adjustVolume(direction, flags); 258 } 259 260 /** 261 * Adds a callback to receive updates from the Session. Updates will be 262 * posted on the caller's thread. 263 * 264 * @param callback The callback object, must not be null. 265 */ 266 public void registerCallback(Callback callback) { 267 registerCallback(callback, null); 268 } 269 270 /** 271 * Adds a callback to receive updates from the session. Updates will be 272 * posted on the specified handler's thread. 273 * 274 * @param callback The callback object, must not be null. 275 * @param handler The handler to post updates on. If null the callers thread 276 * will be used. 277 */ 278 public void registerCallback(Callback callback, Handler handler) { 279 if (callback == null) { 280 throw new IllegalArgumentException("callback cannot be null"); 281 } 282 if (handler == null) { 283 handler = new Handler(); 284 } 285 mImpl.registerCallback(callback, handler); 286 } 287 288 /** 289 * Stop receiving updates on the specified callback. If an update has 290 * already been posted you may still receive it after calling this method. 291 * 292 * @param callback The callback to remove 293 */ 294 public void unregisterCallback(Callback callback) { 295 if (callback == null) { 296 throw new IllegalArgumentException("callback cannot be null"); 297 } 298 mImpl.unregisterCallback(callback); 299 } 300 301 /** 302 * Sends a generic command to the session. It is up to the session creator 303 * to decide what commands and parameters they will support. As such, 304 * commands should only be sent to sessions that the controller owns. 305 * 306 * @param command The command to send 307 * @param params Any parameters to include with the command 308 * @param cb The callback to receive the result on 309 */ 310 public void sendCommand(String command, Bundle params, ResultReceiver cb) { 311 if (TextUtils.isEmpty(command)) { 312 throw new IllegalArgumentException("command cannot be null or empty"); 313 } 314 mImpl.sendCommand(command, params, cb); 315 } 316 317 /** 318 * Get the session owner's package name. 319 * 320 * @return The package name of of the session owner. 321 */ 322 public String getPackageName() { 323 return mImpl.getPackageName(); 324 } 325 326 /** 327 * Gets the underlying framework 328 * {@link android.media.session.MediaController} object. 329 * <p> 330 * This method is only supported on API 21+. 331 * </p> 332 * 333 * @return The underlying {@link android.media.session.MediaController} 334 * object, or null if none. 335 */ 336 public Object getMediaController() { 337 return mImpl.getMediaController(); 338 } 339 340 /** 341 * Callback for receiving updates on from the session. A Callback can be 342 * registered using {@link #registerCallback} 343 */ 344 public static abstract class Callback implements IBinder.DeathRecipient { 345 private final Object mCallbackObj; 346 private MessageHandler mHandler; 347 348 private boolean mRegistered = false; 349 350 public Callback() { 351 if (android.os.Build.VERSION.SDK_INT >= 21) { 352 mCallbackObj = MediaControllerCompatApi21.createCallback(new StubApi21()); 353 } else { 354 mCallbackObj = new StubCompat(); 355 } 356 } 357 358 /** 359 * Override to handle the session being destroyed. The session is no 360 * longer valid after this call and calls to it will be ignored. 361 */ 362 public void onSessionDestroyed() { 363 } 364 365 /** 366 * Override to handle custom events sent by the session owner without a 367 * specified interface. Controllers should only handle these for 368 * sessions they own. 369 * 370 * @param event The event from the session. 371 * @param extras Optional parameters for the event. 372 */ 373 public void onSessionEvent(String event, Bundle extras) { 374 } 375 376 /** 377 * Override to handle changes in playback state. 378 * 379 * @param state The new playback state of the session 380 */ 381 public void onPlaybackStateChanged(PlaybackStateCompat state) { 382 } 383 384 /** 385 * Override to handle changes to the current metadata. 386 * 387 * @param metadata The current metadata for the session or null if none. 388 * @see MediaMetadataCompat 389 */ 390 public void onMetadataChanged(MediaMetadataCompat metadata) { 391 } 392 393 /** 394 * Override to handle changes to items in the queue. 395 * 396 * @see MediaSessionCompat.QueueItem 397 * @param queue A list of items in the current play queue. It should 398 * include the currently playing item as well as previous and 399 * upcoming items if applicable. 400 */ 401 public void onQueueChanged(List<MediaSessionCompat.QueueItem> queue) { 402 } 403 404 /** 405 * Override to handle changes to the queue title. 406 * 407 * @param title The title that should be displayed along with the play 408 * queue such as "Now Playing". May be null if there is no 409 * such title. 410 */ 411 public void onQueueTitleChanged(CharSequence title) { 412 } 413 414 /** 415 * Override to handle chagnes to the {@link MediaSessionCompat} extras. 416 * 417 * @param extras The extras that can include other information 418 * associated with the {@link MediaSessionCompat}. 419 */ 420 public void onExtrasChanged(Bundle extras) { 421 } 422 423 /** 424 * Override to handle changes to the audio info. 425 * 426 * @param info The current audio info for this session. 427 */ 428 public void onAudioInfoChanged(PlaybackInfo info) { 429 } 430 431 @Override 432 public void binderDied() { 433 onSessionDestroyed(); 434 } 435 436 /** 437 * Set the handler to use for pre 21 callbacks. 438 */ 439 private void setHandler(Handler handler) { 440 mHandler = new MessageHandler(handler.getLooper()); 441 } 442 443 private class StubApi21 implements MediaControllerCompatApi21.Callback { 444 @Override 445 public void onSessionDestroyed() { 446 Callback.this.onSessionDestroyed(); 447 } 448 449 @Override 450 public void onSessionEvent(String event, Bundle extras) { 451 Callback.this.onSessionEvent(event, extras); 452 } 453 454 @Override 455 public void onPlaybackStateChanged(Object stateObj) { 456 Callback.this.onPlaybackStateChanged( 457 PlaybackStateCompat.fromPlaybackState(stateObj)); 458 } 459 460 @Override 461 public void onMetadataChanged(Object metadataObj) { 462 Callback.this.onMetadataChanged(MediaMetadataCompat.fromMediaMetadata(metadataObj)); 463 } 464 465 @Override 466 public void onQueueChanged(List<?> queue) { 467 Callback.this.onQueueChanged(QueueItem.fromQueueItemList(queue)); 468 } 469 470 @Override 471 public void onQueueTitleChanged(CharSequence title) { 472 Callback.this.onQueueTitleChanged(title); 473 } 474 475 @Override 476 public void onExtrasChanged(Bundle extras) { 477 Callback.this.onExtrasChanged(extras); 478 } 479 480 @Override 481 public void onAudioInfoChanged( 482 int type, int stream, int control, int max, int current) { 483 Callback.this.onAudioInfoChanged( 484 new PlaybackInfo(type, stream, control, max, current)); 485 } 486 } 487 488 private class StubCompat extends IMediaControllerCallback.Stub { 489 490 @Override 491 public void onEvent(String event, Bundle extras) throws RemoteException { 492 mHandler.post(MessageHandler.MSG_EVENT, event, extras); 493 } 494 495 @Override 496 public void onSessionDestroyed() throws RemoteException { 497 mHandler.post(MessageHandler.MSG_DESTROYED, null, null); 498 } 499 500 @Override 501 public void onPlaybackStateChanged(PlaybackStateCompat state) throws RemoteException { 502 mHandler.post(MessageHandler.MSG_UPDATE_PLAYBACK_STATE, state, null); 503 } 504 505 @Override 506 public void onMetadataChanged(MediaMetadataCompat metadata) throws RemoteException { 507 mHandler.post(MessageHandler.MSG_UPDATE_METADATA, metadata, null); 508 } 509 510 @Override 511 public void onQueueChanged(List<QueueItem> queue) throws RemoteException { 512 mHandler.post(MessageHandler.MSG_UPDATE_QUEUE, queue, null); 513 } 514 515 @Override 516 public void onQueueTitleChanged(CharSequence title) throws RemoteException { 517 mHandler.post(MessageHandler.MSG_UPDATE_QUEUE_TITLE, title, null); 518 } 519 520 @Override 521 public void onExtrasChanged(Bundle extras) throws RemoteException { 522 mHandler.post(MessageHandler.MSG_UPDATE_EXTRAS, extras, null); 523 } 524 525 @Override 526 public void onVolumeInfoChanged(ParcelableVolumeInfo info) throws RemoteException { 527 PlaybackInfo pi = null; 528 if (info != null) { 529 pi = new PlaybackInfo(info.volumeType, info.audioStream, info.controlType, 530 info.maxVolume, info.currentVolume); 531 } 532 mHandler.post(MessageHandler.MSG_UPDATE_VOLUME, pi, null); 533 } 534 } 535 536 private class MessageHandler extends Handler { 537 private static final int MSG_EVENT = 1; 538 private static final int MSG_UPDATE_PLAYBACK_STATE = 2; 539 private static final int MSG_UPDATE_METADATA = 3; 540 private static final int MSG_UPDATE_VOLUME = 4; 541 private static final int MSG_UPDATE_QUEUE = 5; 542 private static final int MSG_UPDATE_QUEUE_TITLE = 6; 543 private static final int MSG_UPDATE_EXTRAS = 7; 544 private static final int MSG_DESTROYED = 8; 545 546 public MessageHandler(Looper looper) { 547 super(looper); 548 } 549 550 @Override 551 public void handleMessage(Message msg) { 552 if (!mRegistered) { 553 return; 554 } 555 switch (msg.what) { 556 case MSG_EVENT: 557 onSessionEvent((String) msg.obj, msg.getData()); 558 break; 559 case MSG_UPDATE_PLAYBACK_STATE: 560 onPlaybackStateChanged((PlaybackStateCompat) msg.obj); 561 break; 562 case MSG_UPDATE_METADATA: 563 onMetadataChanged((MediaMetadataCompat) msg.obj); 564 break; 565 case MSG_UPDATE_QUEUE: 566 onQueueChanged((List<MediaSessionCompat.QueueItem>) msg.obj); 567 break; 568 case MSG_UPDATE_QUEUE_TITLE: 569 onQueueTitleChanged((CharSequence) msg.obj); 570 break; 571 case MSG_UPDATE_EXTRAS: 572 onExtrasChanged((Bundle) msg.obj); 573 break; 574 case MSG_UPDATE_VOLUME: 575 onAudioInfoChanged((PlaybackInfo) msg.obj); 576 break; 577 case MSG_DESTROYED: 578 onSessionDestroyed(); 579 break; 580 } 581 } 582 583 public void post(int what, Object obj, Bundle data) { 584 Message msg = obtainMessage(what, obj); 585 msg.setData(data); 586 msg.sendToTarget(); 587 } 588 } 589 } 590 591 /** 592 * Interface for controlling media playback on a session. This allows an app 593 * to send media transport commands to the session. 594 */ 595 public static abstract class TransportControls { 596 TransportControls() { 597 } 598 599 /** 600 * Request that the player prepare its playback without audio focus. In other words, other 601 * session can continue to play during the preparation of this session. This method can be 602 * used to speed up the start of the playback. Once the preparation is done, the session 603 * will change its playback state to {@link PlaybackStateCompat#STATE_PAUSED}. Afterwards, 604 * {@link #play} can be called to start playback. If the preparation is not needed, 605 * {@link #play} can be directly called without this method. 606 */ 607 public abstract void prepare(); 608 609 /** 610 * Request that the player prepare playback for a specific media id. In other words, other 611 * session can continue to play during the preparation of this session. This method can be 612 * used to speed up the start of the playback. Once the preparation is 613 * done, the session will change its playback state to 614 * {@link PlaybackStateCompat#STATE_PAUSED}. Afterwards, {@link #play} can be called to 615 * start playback. If the preparation is not needed, {@link #playFromMediaId} can 616 * be directly called without this method. 617 * 618 * @param mediaId The id of the requested media. 619 * @param extras Optional extras that can include extra information about the media item 620 * to be prepared. 621 */ 622 public abstract void prepareFromMediaId(String mediaId, Bundle extras); 623 624 /** 625 * Request that the player prepare playback for a specific search query. 626 * An empty or null query should be treated as a request to prepare any 627 * music. In other words, other session can continue to play during 628 * the preparation of this session. This method can be used to speed up the start of the 629 * playback. Once the preparation is done, the session will change its playback state to 630 * {@link PlaybackStateCompat#STATE_PAUSED}. Afterwards, {@link #play} can be called to 631 * start playback. If the preparation is not needed, {@link #playFromSearch} can be directly 632 * called without this method. 633 * 634 * @param query The search query. 635 * @param extras Optional extras that can include extra information 636 * about the query. 637 */ 638 public abstract void prepareFromSearch(String query, Bundle extras); 639 640 /** 641 * Request that the player prepare playback for a specific {@link Uri}. 642 * In other words, other session can continue to play during the preparation of this 643 * session. This method can be used to speed up the start of the playback. 644 * Once the preparation is done, the session will change its playback state to 645 * {@link PlaybackStateCompat#STATE_PAUSED}. Afterwards, {@link #play} can be called to 646 * start playback. If the preparation is not needed, {@link #playFromUri} can be directly 647 * called without this method. 648 * 649 * @param uri The URI of the requested media. 650 * @param extras Optional extras that can include extra information about the media item 651 * to be prepared. 652 */ 653 public abstract void prepareFromUri(Uri uri, Bundle extras); 654 655 /** 656 * Request that the player start its playback at its current position. 657 */ 658 public abstract void play(); 659 660 /** 661 * Request that the player start playback for a specific {@link Uri}. 662 * 663 * @param mediaId The uri of the requested media. 664 * @param extras Optional extras that can include extra information 665 * about the media item to be played. 666 */ 667 public abstract void playFromMediaId(String mediaId, Bundle extras); 668 669 /** 670 * Request that the player start playback for a specific search query. 671 * An empty or null query should be treated as a request to play any 672 * music. 673 * 674 * @param query The search query. 675 * @param extras Optional extras that can include extra information 676 * about the query. 677 */ 678 public abstract void playFromSearch(String query, Bundle extras); 679 680 /** 681 * Request that the player start playback for a specific {@link Uri}. 682 * 683 * @param uri The URI of the requested media. 684 * @param extras Optional extras that can include extra information about the media item 685 * to be played. 686 */ 687 public abstract void playFromUri(Uri uri, Bundle extras); 688 689 /** 690 * Play an item with a specific id in the play queue. If you specify an 691 * id that is not in the play queue, the behavior is undefined. 692 */ 693 public abstract void skipToQueueItem(long id); 694 695 /** 696 * Request that the player pause its playback and stay at its current 697 * position. 698 */ 699 public abstract void pause(); 700 701 /** 702 * Request that the player stop its playback; it may clear its state in 703 * whatever way is appropriate. 704 */ 705 public abstract void stop(); 706 707 /** 708 * Move to a new location in the media stream. 709 * 710 * @param pos Position to move to, in milliseconds. 711 */ 712 public abstract void seekTo(long pos); 713 714 /** 715 * Start fast forwarding. If playback is already fast forwarding this 716 * may increase the rate. 717 */ 718 public abstract void fastForward(); 719 720 /** 721 * Skip to the next item. 722 */ 723 public abstract void skipToNext(); 724 725 /** 726 * Start rewinding. If playback is already rewinding this may increase 727 * the rate. 728 */ 729 public abstract void rewind(); 730 731 /** 732 * Skip to the previous item. 733 */ 734 public abstract void skipToPrevious(); 735 736 /** 737 * Rate the current content. This will cause the rating to be set for 738 * the current user. The Rating type must match the type returned by 739 * {@link #getRatingType()}. 740 * 741 * @param rating The rating to set for the current content 742 */ 743 public abstract void setRating(RatingCompat rating); 744 745 /** 746 * Send a custom action for the {@link MediaSessionCompat} to perform. 747 * 748 * @param customAction The action to perform. 749 * @param args Optional arguments to supply to the 750 * {@link MediaSessionCompat} for this custom action. 751 */ 752 public abstract void sendCustomAction(PlaybackStateCompat.CustomAction customAction, 753 Bundle args); 754 755 /** 756 * Send the id and args from a custom action for the 757 * {@link MediaSessionCompat} to perform. 758 * 759 * @see #sendCustomAction(PlaybackStateCompat.CustomAction action, 760 * Bundle args) 761 * @param action The action identifier of the 762 * {@link PlaybackStateCompat.CustomAction} as specified by 763 * the {@link MediaSessionCompat}. 764 * @param args Optional arguments to supply to the 765 * {@link MediaSessionCompat} for this custom action. 766 */ 767 public abstract void sendCustomAction(String action, Bundle args); 768 } 769 770 /** 771 * Holds information about the way volume is handled for this session. 772 */ 773 public static final class PlaybackInfo { 774 /** 775 * The session uses local playback. 776 */ 777 public static final int PLAYBACK_TYPE_LOCAL = 1; 778 /** 779 * The session uses remote playback. 780 */ 781 public static final int PLAYBACK_TYPE_REMOTE = 2; 782 783 private final int mPlaybackType; 784 // TODO update audio stream with AudioAttributes support version 785 private final int mAudioStream; 786 private final int mVolumeControl; 787 private final int mMaxVolume; 788 private final int mCurrentVolume; 789 790 PlaybackInfo(int type, int stream, int control, int max, int current) { 791 mPlaybackType = type; 792 mAudioStream = stream; 793 mVolumeControl = control; 794 mMaxVolume = max; 795 mCurrentVolume = current; 796 } 797 798 /** 799 * Get the type of volume handling, either local or remote. One of: 800 * <ul> 801 * <li>{@link PlaybackInfo#PLAYBACK_TYPE_LOCAL}</li> 802 * <li>{@link PlaybackInfo#PLAYBACK_TYPE_REMOTE}</li> 803 * </ul> 804 * 805 * @return The type of volume handling this session is using. 806 */ 807 public int getPlaybackType() { 808 return mPlaybackType; 809 } 810 811 /** 812 * Get the stream this is currently controlling volume on. When the volume 813 * type is {@link PlaybackInfo#PLAYBACK_TYPE_REMOTE} this value does not 814 * have meaning and should be ignored. 815 * 816 * @return The stream this session is playing on. 817 */ 818 public int getAudioStream() { 819 // TODO switch to AudioAttributesCompat when it is added. 820 return mAudioStream; 821 } 822 823 /** 824 * Get the type of volume control that can be used. One of: 825 * <ul> 826 * <li>{@link VolumeProviderCompat#VOLUME_CONTROL_ABSOLUTE}</li> 827 * <li>{@link VolumeProviderCompat#VOLUME_CONTROL_RELATIVE}</li> 828 * <li>{@link VolumeProviderCompat#VOLUME_CONTROL_FIXED}</li> 829 * </ul> 830 * 831 * @return The type of volume control that may be used with this 832 * session. 833 */ 834 public int getVolumeControl() { 835 return mVolumeControl; 836 } 837 838 /** 839 * Get the maximum volume that may be set for this session. 840 * 841 * @return The maximum allowed volume where this session is playing. 842 */ 843 public int getMaxVolume() { 844 return mMaxVolume; 845 } 846 847 /** 848 * Get the current volume for this session. 849 * 850 * @return The current volume where this session is playing. 851 */ 852 public int getCurrentVolume() { 853 return mCurrentVolume; 854 } 855 } 856 857 interface MediaControllerImpl { 858 void registerCallback(Callback callback, Handler handler); 859 860 void unregisterCallback(Callback callback); 861 boolean dispatchMediaButtonEvent(KeyEvent keyEvent); 862 TransportControls getTransportControls(); 863 PlaybackStateCompat getPlaybackState(); 864 MediaMetadataCompat getMetadata(); 865 866 List<MediaSessionCompat.QueueItem> getQueue(); 867 CharSequence getQueueTitle(); 868 Bundle getExtras(); 869 int getRatingType(); 870 long getFlags(); 871 PlaybackInfo getPlaybackInfo(); 872 PendingIntent getSessionActivity(); 873 874 void setVolumeTo(int value, int flags); 875 void adjustVolume(int direction, int flags); 876 void sendCommand(String command, Bundle params, ResultReceiver cb); 877 878 String getPackageName(); 879 Object getMediaController(); 880 } 881 882 static class MediaControllerImplBase implements MediaControllerImpl { 883 private MediaSessionCompat.Token mToken; 884 private IMediaSession mBinder; 885 private TransportControls mTransportControls; 886 887 public MediaControllerImplBase(MediaSessionCompat.Token token) { 888 mToken = token; 889 mBinder = IMediaSession.Stub.asInterface((IBinder) token.getToken()); 890 } 891 892 @Override 893 public void registerCallback(Callback callback, Handler handler) { 894 if (callback == null) { 895 throw new IllegalArgumentException("callback may not be null."); 896 } 897 try { 898 mBinder.asBinder().linkToDeath(callback, 0); 899 mBinder.registerCallbackListener((IMediaControllerCallback) callback.mCallbackObj); 900 callback.setHandler(handler); 901 callback.mRegistered = true; 902 } catch (RemoteException e) { 903 Log.e(TAG, "Dead object in registerCallback. " + e); 904 callback.onSessionDestroyed(); 905 } 906 } 907 908 @Override 909 public void unregisterCallback(Callback callback) { 910 if (callback == null) { 911 throw new IllegalArgumentException("callback may not be null."); 912 } 913 try { 914 mBinder.unregisterCallbackListener( 915 (IMediaControllerCallback) callback.mCallbackObj); 916 mBinder.asBinder().unlinkToDeath(callback, 0); 917 callback.mRegistered = false; 918 } catch (RemoteException e) { 919 Log.e(TAG, "Dead object in unregisterCallback. " + e); 920 } 921 } 922 923 @Override 924 public boolean dispatchMediaButtonEvent(KeyEvent event) { 925 if (event == null) { 926 throw new IllegalArgumentException("event may not be null."); 927 } 928 try { 929 mBinder.sendMediaButton(event); 930 } catch (RemoteException e) { 931 Log.e(TAG, "Dead object in dispatchMediaButtonEvent. " + e); 932 } 933 return false; 934 } 935 936 @Override 937 public TransportControls getTransportControls() { 938 if (mTransportControls == null) { 939 mTransportControls = new TransportControlsBase(mBinder); 940 } 941 942 return mTransportControls; 943 } 944 945 @Override 946 public PlaybackStateCompat getPlaybackState() { 947 try { 948 return mBinder.getPlaybackState(); 949 } catch (RemoteException e) { 950 Log.e(TAG, "Dead object in getPlaybackState. " + e); 951 } 952 return null; 953 } 954 955 @Override 956 public MediaMetadataCompat getMetadata() { 957 try { 958 return mBinder.getMetadata(); 959 } catch (RemoteException e) { 960 Log.e(TAG, "Dead object in getMetadata. " + e); 961 } 962 return null; 963 } 964 965 @Override 966 public List<MediaSessionCompat.QueueItem> getQueue() { 967 try { 968 return mBinder.getQueue(); 969 } catch (RemoteException e) { 970 Log.e(TAG, "Dead object in getQueue. " + e); 971 } 972 return null; 973 } 974 975 @Override 976 public CharSequence getQueueTitle() { 977 try { 978 return mBinder.getQueueTitle(); 979 } catch (RemoteException e) { 980 Log.e(TAG, "Dead object in getQueueTitle. " + e); 981 } 982 return null; 983 } 984 985 @Override 986 public Bundle getExtras() { 987 try { 988 return mBinder.getExtras(); 989 } catch (RemoteException e) { 990 Log.e(TAG, "Dead object in getExtras. " + e); 991 } 992 return null; 993 } 994 995 @Override 996 public int getRatingType() { 997 try { 998 return mBinder.getRatingType(); 999 } catch (RemoteException e) { 1000 Log.e(TAG, "Dead object in getRatingType. " + e); 1001 } 1002 return 0; 1003 } 1004 1005 @Override 1006 public long getFlags() { 1007 try { 1008 return mBinder.getFlags(); 1009 } catch (RemoteException e) { 1010 Log.e(TAG, "Dead object in getFlags. " + e); 1011 } 1012 return 0; 1013 } 1014 1015 @Override 1016 public PlaybackInfo getPlaybackInfo() { 1017 try { 1018 ParcelableVolumeInfo info = mBinder.getVolumeAttributes(); 1019 PlaybackInfo pi = new PlaybackInfo(info.volumeType, info.audioStream, 1020 info.controlType, info.maxVolume, info.currentVolume); 1021 return pi; 1022 } catch (RemoteException e) { 1023 Log.e(TAG, "Dead object in getPlaybackInfo. " + e); 1024 } 1025 return null; 1026 } 1027 1028 @Override 1029 public PendingIntent getSessionActivity() { 1030 try { 1031 return mBinder.getLaunchPendingIntent(); 1032 } catch (RemoteException e) { 1033 Log.e(TAG, "Dead object in getSessionActivity. " + e); 1034 } 1035 return null; 1036 } 1037 1038 @Override 1039 public void setVolumeTo(int value, int flags) { 1040 try { 1041 mBinder.setVolumeTo(value, flags, null); 1042 } catch (RemoteException e) { 1043 Log.e(TAG, "Dead object in setVolumeTo. " + e); 1044 } 1045 } 1046 1047 @Override 1048 public void adjustVolume(int direction, int flags) { 1049 try { 1050 mBinder.adjustVolume(direction, flags, null); 1051 } catch (RemoteException e) { 1052 Log.e(TAG, "Dead object in adjustVolume. " + e); 1053 } 1054 } 1055 1056 @Override 1057 public void sendCommand(String command, Bundle params, ResultReceiver cb) { 1058 try { 1059 mBinder.sendCommand(command, params, 1060 new MediaSessionCompat.ResultReceiverWrapper(cb)); 1061 } catch (RemoteException e) { 1062 Log.e(TAG, "Dead object in sendCommand. " + e); 1063 } 1064 } 1065 1066 @Override 1067 public String getPackageName() { 1068 try { 1069 return mBinder.getPackageName(); 1070 } catch (RemoteException e) { 1071 Log.e(TAG, "Dead object in getPackageName. " + e); 1072 } 1073 return null; 1074 } 1075 1076 @Override 1077 public Object getMediaController() { 1078 return null; 1079 } 1080 } 1081 1082 static class TransportControlsBase extends TransportControls { 1083 private IMediaSession mBinder; 1084 1085 public TransportControlsBase(IMediaSession binder) { 1086 mBinder = binder; 1087 } 1088 1089 @Override 1090 public void prepare() { 1091 try { 1092 mBinder.prepare(); 1093 } catch (RemoteException e) { 1094 Log.e(TAG, "Dead object in prepare. " + e); 1095 } 1096 } 1097 1098 @Override 1099 public void prepareFromMediaId(String mediaId, Bundle extras) { 1100 try { 1101 mBinder.prepareFromMediaId(mediaId, extras); 1102 } catch (RemoteException e) { 1103 Log.e(TAG, "Dead object in prepareFromMediaId. " + e); 1104 } 1105 } 1106 1107 @Override 1108 public void prepareFromSearch(String query, Bundle extras) { 1109 try { 1110 mBinder.prepareFromSearch(query, extras); 1111 } catch (RemoteException e) { 1112 Log.e(TAG, "Dead object in prepareFromSearch. " + e); 1113 } 1114 } 1115 1116 @Override 1117 public void prepareFromUri(Uri uri, Bundle extras) { 1118 try { 1119 mBinder.prepareFromUri(uri, extras); 1120 } catch (RemoteException e) { 1121 Log.e(TAG, "Dead object in prepareFromUri. " + e); 1122 } 1123 } 1124 1125 @Override 1126 public void play() { 1127 try { 1128 mBinder.play(); 1129 } catch (RemoteException e) { 1130 Log.e(TAG, "Dead object in play. " + e); 1131 } 1132 } 1133 1134 @Override 1135 public void playFromMediaId(String mediaId, Bundle extras) { 1136 try { 1137 mBinder.playFromMediaId(mediaId, extras); 1138 } catch (RemoteException e) { 1139 Log.e(TAG, "Dead object in playFromMediaId. " + e); 1140 } 1141 } 1142 1143 @Override 1144 public void playFromSearch(String query, Bundle extras) { 1145 try { 1146 mBinder.playFromSearch(query, extras); 1147 } catch (RemoteException e) { 1148 Log.e(TAG, "Dead object in playFromSearch. " + e); 1149 } 1150 } 1151 1152 @Override 1153 public void playFromUri(Uri uri, Bundle extras) { 1154 try { 1155 mBinder.playFromUri(uri, extras); 1156 } catch (RemoteException e) { 1157 Log.e(TAG, "Dead object in playFromUri. " + e); 1158 } 1159 } 1160 1161 @Override 1162 public void skipToQueueItem(long id) { 1163 try { 1164 mBinder.skipToQueueItem(id); 1165 } catch (RemoteException e) { 1166 Log.e(TAG, "Dead object in skipToQueueItem. " + e); 1167 } 1168 } 1169 1170 @Override 1171 public void pause() { 1172 try { 1173 mBinder.pause(); 1174 } catch (RemoteException e) { 1175 Log.e(TAG, "Dead object in pause. " + e); 1176 } 1177 } 1178 1179 @Override 1180 public void stop() { 1181 try { 1182 mBinder.stop(); 1183 } catch (RemoteException e) { 1184 Log.e(TAG, "Dead object in stop. " + e); 1185 } 1186 } 1187 1188 @Override 1189 public void seekTo(long pos) { 1190 try { 1191 mBinder.seekTo(pos); 1192 } catch (RemoteException e) { 1193 Log.e(TAG, "Dead object in seekTo. " + e); 1194 } 1195 } 1196 1197 @Override 1198 public void fastForward() { 1199 try { 1200 mBinder.fastForward(); 1201 } catch (RemoteException e) { 1202 Log.e(TAG, "Dead object in fastForward. " + e); 1203 } 1204 } 1205 1206 @Override 1207 public void skipToNext() { 1208 try { 1209 mBinder.next(); 1210 } catch (RemoteException e) { 1211 Log.e(TAG, "Dead object in skipToNext. " + e); 1212 } 1213 } 1214 1215 @Override 1216 public void rewind() { 1217 try { 1218 mBinder.rewind(); 1219 } catch (RemoteException e) { 1220 Log.e(TAG, "Dead object in rewind. " + e); 1221 } 1222 } 1223 1224 @Override 1225 public void skipToPrevious() { 1226 try { 1227 mBinder.previous(); 1228 } catch (RemoteException e) { 1229 Log.e(TAG, "Dead object in skipToPrevious. " + e); 1230 } 1231 } 1232 1233 @Override 1234 public void setRating(RatingCompat rating) { 1235 try { 1236 mBinder.rate(rating); 1237 } catch (RemoteException e) { 1238 Log.e(TAG, "Dead object in setRating. " + e); 1239 } 1240 } 1241 1242 @Override 1243 public void sendCustomAction(CustomAction customAction, Bundle args) { 1244 sendCustomAction(customAction.getAction(), args); 1245 } 1246 1247 @Override 1248 public void sendCustomAction(String action, Bundle args) { 1249 try { 1250 mBinder.sendCustomAction(action, args); 1251 } catch (RemoteException e) { 1252 Log.e(TAG, "Dead object in sendCustomAction. " + e); 1253 } 1254 } 1255 } 1256 1257 static class MediaControllerImplApi21 implements MediaControllerImpl { 1258 protected final Object mControllerObj; 1259 1260 public MediaControllerImplApi21(Context context, MediaSessionCompat session) { 1261 mControllerObj = MediaControllerCompatApi21.fromToken(context, 1262 session.getSessionToken().getToken()); 1263 } 1264 1265 public MediaControllerImplApi21(Context context, MediaSessionCompat.Token sessionToken) 1266 throws RemoteException { 1267 mControllerObj = MediaControllerCompatApi21.fromToken(context, 1268 sessionToken.getToken()); 1269 if (mControllerObj == null) throw new RemoteException(); 1270 } 1271 1272 @Override 1273 public void registerCallback(Callback callback, Handler handler) { 1274 MediaControllerCompatApi21.registerCallback(mControllerObj, callback.mCallbackObj, handler); 1275 } 1276 1277 @Override 1278 public void unregisterCallback(Callback callback) { 1279 MediaControllerCompatApi21.unregisterCallback(mControllerObj, callback.mCallbackObj); 1280 } 1281 1282 @Override 1283 public boolean dispatchMediaButtonEvent(KeyEvent event) { 1284 return MediaControllerCompatApi21.dispatchMediaButtonEvent(mControllerObj, event); 1285 } 1286 1287 @Override 1288 public TransportControls getTransportControls() { 1289 Object controlsObj = MediaControllerCompatApi21.getTransportControls(mControllerObj); 1290 return controlsObj != null ? new TransportControlsApi21(controlsObj) : null; 1291 } 1292 1293 @Override 1294 public PlaybackStateCompat getPlaybackState() { 1295 Object stateObj = MediaControllerCompatApi21.getPlaybackState(mControllerObj); 1296 return stateObj != null ? PlaybackStateCompat.fromPlaybackState(stateObj) : null; 1297 } 1298 1299 @Override 1300 public MediaMetadataCompat getMetadata() { 1301 Object metadataObj = MediaControllerCompatApi21.getMetadata(mControllerObj); 1302 return metadataObj != null ? MediaMetadataCompat.fromMediaMetadata(metadataObj) : null; 1303 } 1304 1305 @Override 1306 public List<MediaSessionCompat.QueueItem> getQueue() { 1307 List<Object> queueObjs = MediaControllerCompatApi21.getQueue(mControllerObj); 1308 return queueObjs != null ? MediaSessionCompat.QueueItem.fromQueueItemList(queueObjs) 1309 : null; 1310 } 1311 1312 @Override 1313 public CharSequence getQueueTitle() { 1314 return MediaControllerCompatApi21.getQueueTitle(mControllerObj); 1315 } 1316 1317 @Override 1318 public Bundle getExtras() { 1319 return MediaControllerCompatApi21.getExtras(mControllerObj); 1320 } 1321 1322 @Override 1323 public int getRatingType() { 1324 return MediaControllerCompatApi21.getRatingType(mControllerObj); 1325 } 1326 1327 @Override 1328 public long getFlags() { 1329 return MediaControllerCompatApi21.getFlags(mControllerObj); 1330 } 1331 1332 @Override 1333 public PlaybackInfo getPlaybackInfo() { 1334 Object volumeInfoObj = MediaControllerCompatApi21.getPlaybackInfo(mControllerObj); 1335 return volumeInfoObj != null ? new PlaybackInfo( 1336 MediaControllerCompatApi21.PlaybackInfo.getPlaybackType(volumeInfoObj), 1337 MediaControllerCompatApi21.PlaybackInfo.getLegacyAudioStream(volumeInfoObj), 1338 MediaControllerCompatApi21.PlaybackInfo.getVolumeControl(volumeInfoObj), 1339 MediaControllerCompatApi21.PlaybackInfo.getMaxVolume(volumeInfoObj), 1340 MediaControllerCompatApi21.PlaybackInfo.getCurrentVolume(volumeInfoObj)) : null; 1341 } 1342 1343 @Override 1344 public PendingIntent getSessionActivity() { 1345 return MediaControllerCompatApi21.getSessionActivity(mControllerObj); 1346 } 1347 1348 @Override 1349 public void setVolumeTo(int value, int flags) { 1350 MediaControllerCompatApi21.setVolumeTo(mControllerObj, value, flags); 1351 } 1352 1353 @Override 1354 public void adjustVolume(int direction, int flags) { 1355 MediaControllerCompatApi21.adjustVolume(mControllerObj, direction, flags); 1356 } 1357 1358 @Override 1359 public void sendCommand(String command, Bundle params, ResultReceiver cb) { 1360 MediaControllerCompatApi21.sendCommand(mControllerObj, command, params, cb); 1361 } 1362 1363 @Override 1364 public String getPackageName() { 1365 return MediaControllerCompatApi21.getPackageName(mControllerObj); 1366 } 1367 1368 @Override 1369 public Object getMediaController() { 1370 return mControllerObj; 1371 } 1372 } 1373 1374 static class TransportControlsApi21 extends TransportControls { 1375 protected final Object mControlsObj; 1376 1377 public TransportControlsApi21(Object controlsObj) { 1378 mControlsObj = controlsObj; 1379 } 1380 1381 @Override 1382 public void prepare() { 1383 sendCustomAction(MediaSessionCompat.ACTION_PREPARE, null); 1384 } 1385 1386 @Override 1387 public void prepareFromMediaId(String mediaId, Bundle extras) { 1388 Bundle bundle = new Bundle(); 1389 bundle.putString(MediaSessionCompat.ACTION_ARGUMENT_MEDIA_ID, mediaId); 1390 bundle.putBundle(MediaSessionCompat.ACTION_ARGUMENT_EXTRAS, extras); 1391 sendCustomAction(MediaSessionCompat.ACTION_PREPARE_FROM_MEDIA_ID, bundle); 1392 } 1393 1394 @Override 1395 public void prepareFromSearch(String query, Bundle extras) { 1396 Bundle bundle = new Bundle(); 1397 bundle.putString(MediaSessionCompat.ACTION_ARGUMENT_QUERY, query); 1398 bundle.putBundle(MediaSessionCompat.ACTION_ARGUMENT_EXTRAS, extras); 1399 sendCustomAction(MediaSessionCompat.ACTION_PREPARE_FROM_SEARCH, bundle); 1400 } 1401 1402 @Override 1403 public void prepareFromUri(Uri uri, Bundle extras) { 1404 Bundle bundle = new Bundle(); 1405 bundle.putParcelable(MediaSessionCompat.ACTION_ARGUMENT_URI, uri); 1406 bundle.putBundle(MediaSessionCompat.ACTION_ARGUMENT_EXTRAS, extras); 1407 sendCustomAction(MediaSessionCompat.ACTION_PREPARE_FROM_URI, bundle); 1408 } 1409 1410 @Override 1411 public void play() { 1412 MediaControllerCompatApi21.TransportControls.play(mControlsObj); 1413 } 1414 1415 @Override 1416 public void pause() { 1417 MediaControllerCompatApi21.TransportControls.pause(mControlsObj); 1418 } 1419 1420 @Override 1421 public void stop() { 1422 MediaControllerCompatApi21.TransportControls.stop(mControlsObj); 1423 } 1424 1425 @Override 1426 public void seekTo(long pos) { 1427 MediaControllerCompatApi21.TransportControls.seekTo(mControlsObj, pos); 1428 } 1429 1430 @Override 1431 public void fastForward() { 1432 MediaControllerCompatApi21.TransportControls.fastForward(mControlsObj); 1433 } 1434 1435 @Override 1436 public void rewind() { 1437 MediaControllerCompatApi21.TransportControls.rewind(mControlsObj); 1438 } 1439 1440 @Override 1441 public void skipToNext() { 1442 MediaControllerCompatApi21.TransportControls.skipToNext(mControlsObj); 1443 } 1444 1445 @Override 1446 public void skipToPrevious() { 1447 MediaControllerCompatApi21.TransportControls.skipToPrevious(mControlsObj); 1448 } 1449 1450 @Override 1451 public void setRating(RatingCompat rating) { 1452 MediaControllerCompatApi21.TransportControls.setRating(mControlsObj, 1453 rating != null ? rating.getRating() : null); 1454 } 1455 1456 @Override 1457 public void playFromMediaId(String mediaId, Bundle extras) { 1458 MediaControllerCompatApi21.TransportControls.playFromMediaId(mControlsObj, mediaId, 1459 extras); 1460 } 1461 1462 @Override 1463 public void playFromSearch(String query, Bundle extras) { 1464 MediaControllerCompatApi21.TransportControls.playFromSearch(mControlsObj, query, 1465 extras); 1466 } 1467 1468 @Override 1469 public void playFromUri(Uri uri, Bundle extras) { 1470 if (uri == null || Uri.EMPTY.equals(uri)) { 1471 throw new IllegalArgumentException( 1472 "You must specify a non-empty Uri for playFromUri."); 1473 } 1474 Bundle bundle = new Bundle(); 1475 bundle.putParcelable(MediaSessionCompat.ACTION_ARGUMENT_URI, uri); 1476 bundle.putParcelable(MediaSessionCompat.ACTION_ARGUMENT_EXTRAS, extras); 1477 sendCustomAction(MediaSessionCompat.ACTION_PLAY_FROM_URI, bundle); 1478 } 1479 1480 @Override 1481 public void skipToQueueItem(long id) { 1482 MediaControllerCompatApi21.TransportControls.skipToQueueItem(mControlsObj, id); 1483 } 1484 1485 @Override 1486 public void sendCustomAction(CustomAction customAction, Bundle args) { 1487 MediaControllerCompatApi21.TransportControls.sendCustomAction(mControlsObj, 1488 customAction.getAction(), args); 1489 } 1490 1491 @Override 1492 public void sendCustomAction(String action, Bundle args) { 1493 MediaControllerCompatApi21.TransportControls.sendCustomAction(mControlsObj, action, 1494 args); 1495 } 1496 } 1497 1498 static class MediaControllerImplApi23 extends MediaControllerImplApi21 { 1499 1500 public MediaControllerImplApi23(Context context, MediaSessionCompat session) { 1501 super(context, session); 1502 } 1503 1504 public MediaControllerImplApi23(Context context, MediaSessionCompat.Token sessionToken) 1505 throws RemoteException { 1506 super(context, sessionToken); 1507 } 1508 1509 @Override 1510 public TransportControls getTransportControls() { 1511 Object controlsObj = MediaControllerCompatApi21.getTransportControls(mControllerObj); 1512 return controlsObj != null ? new TransportControlsApi23(controlsObj) : null; 1513 } 1514 } 1515 1516 static class TransportControlsApi23 extends TransportControlsApi21 { 1517 1518 public TransportControlsApi23(Object controlsObj) { 1519 super(controlsObj); 1520 } 1521 1522 @Override 1523 public void playFromUri(Uri uri, Bundle extras) { 1524 MediaControllerCompatApi23.TransportControls.playFromUri(mControlsObj, uri, 1525 extras); 1526 } 1527 } 1528 1529 static class MediaControllerImplApi24 extends MediaControllerImplApi23 { 1530 1531 public MediaControllerImplApi24(Context context, MediaSessionCompat session) { 1532 super(context, session); 1533 } 1534 1535 public MediaControllerImplApi24(Context context, MediaSessionCompat.Token sessionToken) 1536 throws RemoteException { 1537 super(context, sessionToken); 1538 } 1539 1540 @Override 1541 public TransportControls getTransportControls() { 1542 Object controlsObj = MediaControllerCompatApi21.getTransportControls(mControllerObj); 1543 return controlsObj != null ? new TransportControlsApi24(controlsObj) : null; 1544 } 1545 } 1546 1547 static class TransportControlsApi24 extends TransportControlsApi23 { 1548 1549 public TransportControlsApi24(Object controlsObj) { 1550 super(controlsObj); 1551 } 1552 1553 @Override 1554 public void prepare() { 1555 MediaControllerCompatApi24.TransportControls.prepare(mControlsObj); 1556 } 1557 1558 @Override 1559 public void prepareFromMediaId(String mediaId, Bundle extras) { 1560 MediaControllerCompatApi24.TransportControls.prepareFromMediaId( 1561 mControlsObj, mediaId, extras); 1562 } 1563 1564 @Override 1565 public void prepareFromSearch(String query, Bundle extras) { 1566 MediaControllerCompatApi24.TransportControls.prepareFromSearch( 1567 mControlsObj, query, extras); 1568 } 1569 1570 @Override 1571 public void prepareFromUri(Uri uri, Bundle extras) { 1572 MediaControllerCompatApi24.TransportControls.prepareFromUri(mControlsObj, uri, extras); 1573 } 1574 } 1575 1576} 1577