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 android.media; 18 19 import static android.media.MediaPlayerBase.BUFFERING_STATE_UNKNOWN; 20 21 import android.annotation.CallbackExecutor; 22 import android.annotation.IntDef; 23 import android.annotation.NonNull; 24 import android.annotation.Nullable; 25 import android.app.PendingIntent; 26 import android.content.Context; 27 import android.content.Intent; 28 import android.media.MediaPlayerBase.BuffState; 29 import android.media.MediaPlayerBase.PlayerState; 30 import android.media.MediaPlaylistAgent.RepeatMode; 31 import android.media.MediaPlaylistAgent.ShuffleMode; 32 import android.media.update.ApiLoader; 33 import android.media.update.MediaSession2Provider; 34 import android.media.update.MediaSession2Provider.BuilderBaseProvider; 35 import android.media.update.MediaSession2Provider.CommandButtonProvider; 36 import android.media.update.MediaSession2Provider.ControllerInfoProvider; 37 import android.media.update.ProviderCreator; 38 import android.net.Uri; 39 import android.os.Bundle; 40 import android.os.IInterface; 41 import android.os.ResultReceiver; 42 43 import java.lang.annotation.Retention; 44 import java.lang.annotation.RetentionPolicy; 45 import java.util.List; 46 import java.util.concurrent.Executor; 47 48 /** 49 * @hide 50 * Allows a media app to expose its transport controls and playback information in a process to 51 * other processes including the Android framework and other apps. Common use cases are as follows. 52 * <ul> 53 * <li>Bluetooth/wired headset key events support</li> 54 * <li>Android Auto/Wearable support</li> 55 * <li>Separating UI process and playback process</li> 56 * </ul> 57 * <p> 58 * A MediaSession2 should be created when an app wants to publish media playback information or 59 * handle media keys. In general an app only needs one session for all playback, though multiple 60 * sessions can be created to provide finer grain controls of media. 61 * <p> 62 * If you want to support background playback, {@link MediaSessionService2} is preferred 63 * instead. With it, your playback can be revived even after playback is finished. See 64 * {@link MediaSessionService2} for details. 65 * <p> 66 * A session can be obtained by {@link Builder}. The owner of the session may pass its session token 67 * to other processes to allow them to create a {@link MediaController2} to interact with the 68 * session. 69 * <p> 70 * When a session receive transport control commands, the session sends the commands directly to 71 * the the underlying media player set by {@link Builder} or 72 * {@link #updatePlayer}. 73 * <p> 74 * When an app is finished performing playback it must call {@link #close()} to clean up the session 75 * and notify any controllers. 76 * <p> 77 * {@link MediaSession2} objects should be used on the thread on the looper. 78 * 79 * @see MediaSessionService2 80 */ 81 public class MediaSession2 implements AutoCloseable { 82 private final MediaSession2Provider mProvider; 83 84 /** 85 * @hide 86 */ 87 @IntDef({ERROR_CODE_UNKNOWN_ERROR, ERROR_CODE_APP_ERROR, ERROR_CODE_NOT_SUPPORTED, 88 ERROR_CODE_AUTHENTICATION_EXPIRED, ERROR_CODE_PREMIUM_ACCOUNT_REQUIRED, 89 ERROR_CODE_CONCURRENT_STREAM_LIMIT, ERROR_CODE_PARENTAL_CONTROL_RESTRICTED, 90 ERROR_CODE_NOT_AVAILABLE_IN_REGION, ERROR_CODE_CONTENT_ALREADY_PLAYING, 91 ERROR_CODE_SKIP_LIMIT_REACHED, ERROR_CODE_ACTION_ABORTED, ERROR_CODE_END_OF_QUEUE, 92 ERROR_CODE_SETUP_REQUIRED}) 93 @Retention(RetentionPolicy.SOURCE) 94 public @interface ErrorCode {} 95 96 /** 97 * This is the default error code and indicates that none of the other error codes applies. 98 */ 99 public static final int ERROR_CODE_UNKNOWN_ERROR = 0; 100 101 /** 102 * Error code when the application state is invalid to fulfill the request. 103 */ 104 public static final int ERROR_CODE_APP_ERROR = 1; 105 106 /** 107 * Error code when the request is not supported by the application. 108 */ 109 public static final int ERROR_CODE_NOT_SUPPORTED = 2; 110 111 /** 112 * Error code when the request cannot be performed because authentication has expired. 113 */ 114 public static final int ERROR_CODE_AUTHENTICATION_EXPIRED = 3; 115 116 /** 117 * Error code when a premium account is required for the request to succeed. 118 */ 119 public static final int ERROR_CODE_PREMIUM_ACCOUNT_REQUIRED = 4; 120 121 /** 122 * Error code when too many concurrent streams are detected. 123 */ 124 public static final int ERROR_CODE_CONCURRENT_STREAM_LIMIT = 5; 125 126 /** 127 * Error code when the content is blocked due to parental controls. 128 */ 129 public static final int ERROR_CODE_PARENTAL_CONTROL_RESTRICTED = 6; 130 131 /** 132 * Error code when the content is blocked due to being regionally unavailable. 133 */ 134 public static final int ERROR_CODE_NOT_AVAILABLE_IN_REGION = 7; 135 136 /** 137 * Error code when the requested content is already playing. 138 */ 139 public static final int ERROR_CODE_CONTENT_ALREADY_PLAYING = 8; 140 141 /** 142 * Error code when the application cannot skip any more songs because skip limit is reached. 143 */ 144 public static final int ERROR_CODE_SKIP_LIMIT_REACHED = 9; 145 146 /** 147 * Error code when the action is interrupted due to some external event. 148 */ 149 public static final int ERROR_CODE_ACTION_ABORTED = 10; 150 151 /** 152 * Error code when the playback navigation (previous, next) is not possible because the queue 153 * was exhausted. 154 */ 155 public static final int ERROR_CODE_END_OF_QUEUE = 11; 156 157 /** 158 * Error code when the session needs user's manual intervention. 159 */ 160 public static final int ERROR_CODE_SETUP_REQUIRED = 12; 161 162 /** 163 * Interface definition of a callback to be invoked when a {@link MediaItem2} in the playlist 164 * didn't have a {@link DataSourceDesc} but it's needed now for preparing or playing it. 165 * 166 * #see #setOnDataSourceMissingHelper 167 */ 168 public interface OnDataSourceMissingHelper { 169 /** 170 * Called when a {@link MediaItem2} in the playlist didn't have a {@link DataSourceDesc} 171 * but it's needed now for preparing or playing it. Returned data source descriptor will be 172 * sent to the player directly to prepare or play the contents. 173 * <p> 174 * An exception may be thrown if the returned {@link DataSourceDesc} is duplicated in the 175 * playlist, so items cannot be differentiated. 176 * 177 * @param session the session for this event 178 * @param item media item from the controller 179 * @return a data source descriptor if the media item. Can be {@code null} if the content 180 * isn't available. 181 */ 182 @Nullable DataSourceDesc onDataSourceMissing(@NonNull MediaSession2 session, 183 @NonNull MediaItem2 item); 184 } 185 186 /** 187 * Callback to be called for all incoming commands from {@link MediaController2}s. 188 * <p> 189 * If it's not set, the session will accept all controllers and all incoming commands by 190 * default. 191 */ 192 // TODO(jaewan): Move this to updatable for default implementation (b/74091963) 193 public static abstract class SessionCallback { 194 /** 195 * Called when a controller is created for this session. Return allowed commands for 196 * controller. By default it allows all connection requests and commands. 197 * <p> 198 * You can reject the connection by return {@code null}. In that case, controller receives 199 * {@link MediaController2.ControllerCallback#onDisconnected(MediaController2)} and cannot 200 * be usable. 201 * 202 * @param session the session for this event 203 * @param controller controller information. 204 * @return allowed commands. Can be {@code null} to reject connection. 205 */ 206 public @Nullable SessionCommandGroup2 onConnect(@NonNull MediaSession2 session, 207 @NonNull ControllerInfo controller) { 208 SessionCommandGroup2 commands = new SessionCommandGroup2(); 209 commands.addAllPredefinedCommands(); 210 return commands; 211 } 212 213 /** 214 * Called when a controller is disconnected 215 * 216 * @param session the session for this event 217 * @param controller controller information 218 */ 219 public void onDisconnected(@NonNull MediaSession2 session, 220 @NonNull ControllerInfo controller) { } 221 222 /** 223 * Called when a controller sent a command that will be sent directly to the player. Return 224 * {@code false} here to reject the request and stop sending command to the player. 225 * 226 * @param session the session for this event 227 * @param controller controller information. 228 * @param command a command. This method will be called for every single command. 229 * @return {@code true} if you want to accept incoming command. {@code false} otherwise. 230 * @see SessionCommand2#COMMAND_CODE_PLAYBACK_PLAY 231 * @see SessionCommand2#COMMAND_CODE_PLAYBACK_PAUSE 232 * @see SessionCommand2#COMMAND_CODE_PLAYBACK_STOP 233 * @see SessionCommand2#COMMAND_CODE_PLAYLIST_SKIP_NEXT_ITEM 234 * @see SessionCommand2#COMMAND_CODE_PLAYLIST_SKIP_PREV_ITEM 235 * @see SessionCommand2#COMMAND_CODE_PLAYBACK_PREPARE 236 * @see SessionCommand2#COMMAND_CODE_SESSION_FAST_FORWARD 237 * @see SessionCommand2#COMMAND_CODE_SESSION_REWIND 238 * @see SessionCommand2#COMMAND_CODE_PLAYBACK_SEEK_TO 239 * @see SessionCommand2#COMMAND_CODE_PLAYLIST_SKIP_TO_PLAYLIST_ITEM 240 * @see SessionCommand2#COMMAND_CODE_PLAYLIST_ADD_ITEM 241 * @see SessionCommand2#COMMAND_CODE_PLAYLIST_REMOVE_ITEM 242 * @see SessionCommand2#COMMAND_CODE_PLAYLIST_GET_LIST 243 * @see SessionCommand2#COMMAND_CODE_SET_VOLUME 244 */ 245 public boolean onCommandRequest(@NonNull MediaSession2 session, 246 @NonNull ControllerInfo controller, @NonNull SessionCommand2 command) { 247 return true; 248 } 249 250 /** 251 * Called when a controller set rating of a media item through 252 * {@link MediaController2#setRating(String, Rating2)}. 253 * <p> 254 * To allow setting user rating for a {@link MediaItem2}, the media item's metadata 255 * should have {@link Rating2} with the key {@link MediaMetadata#METADATA_KEY_USER_RATING}, 256 * in order to provide possible rating style for controller. Controller will follow the 257 * rating style. 258 * 259 * @param session the session for this event 260 * @param controller controller information 261 * @param mediaId media id from the controller 262 * @param rating new rating from the controller 263 */ 264 public void onSetRating(@NonNull MediaSession2 session, @NonNull ControllerInfo controller, 265 @NonNull String mediaId, @NonNull Rating2 rating) { } 266 267 /** 268 * Called when a controller sent a custom command through 269 * {@link MediaController2#sendCustomCommand(SessionCommand2, Bundle, ResultReceiver)}. 270 * 271 * @param session the session for this event 272 * @param controller controller information 273 * @param customCommand custom command. 274 * @param args optional arguments 275 * @param cb optional result receiver 276 */ 277 public void onCustomCommand(@NonNull MediaSession2 session, 278 @NonNull ControllerInfo controller, @NonNull SessionCommand2 customCommand, 279 @Nullable Bundle args, @Nullable ResultReceiver cb) { } 280 281 /** 282 * Called when a controller requested to play a specific mediaId through 283 * {@link MediaController2#playFromMediaId(String, Bundle)}. 284 * 285 * @param session the session for this event 286 * @param controller controller information 287 * @param mediaId media id 288 * @param extras optional extra bundle 289 * @see SessionCommand2#COMMAND_CODE_SESSION_PLAY_FROM_MEDIA_ID 290 */ 291 public void onPlayFromMediaId(@NonNull MediaSession2 session, 292 @NonNull ControllerInfo controller, @NonNull String mediaId, 293 @Nullable Bundle extras) { } 294 295 /** 296 * Called when a controller requested to begin playback from a search query through 297 * {@link MediaController2#playFromSearch(String, Bundle)} 298 * <p> 299 * An empty query indicates that the app may play any music. The implementation should 300 * attempt to make a smart choice about what to play. 301 * 302 * @param session the session for this event 303 * @param controller controller information 304 * @param query query string. Can be empty to indicate any suggested media 305 * @param extras optional extra bundle 306 * @see SessionCommand2#COMMAND_CODE_SESSION_PLAY_FROM_SEARCH 307 */ 308 public void onPlayFromSearch(@NonNull MediaSession2 session, 309 @NonNull ControllerInfo controller, @NonNull String query, 310 @Nullable Bundle extras) { } 311 312 /** 313 * Called when a controller requested to play a specific media item represented by a URI 314 * through {@link MediaController2#playFromUri(Uri, Bundle)} 315 * 316 * @param session the session for this event 317 * @param controller controller information 318 * @param uri uri 319 * @param extras optional extra bundle 320 * @see SessionCommand2#COMMAND_CODE_SESSION_PLAY_FROM_URI 321 */ 322 public void onPlayFromUri(@NonNull MediaSession2 session, 323 @NonNull ControllerInfo controller, @NonNull Uri uri, 324 @Nullable Bundle extras) { } 325 326 /** 327 * Called when a controller requested to prepare for playing a specific mediaId through 328 * {@link MediaController2#prepareFromMediaId(String, Bundle)}. 329 * <p> 330 * During the preparation, a session should not hold audio focus in order to allow other 331 * sessions play seamlessly. The state of playback should be updated to 332 * {@link MediaPlayerBase#PLAYER_STATE_PAUSED} after the preparation is done. 333 * <p> 334 * The playback of the prepared content should start in the later calls of 335 * {@link MediaSession2#play()}. 336 * <p> 337 * Override {@link #onPlayFromMediaId} to handle requests for starting 338 * playback without preparation. 339 * 340 * @param session the session for this event 341 * @param controller controller information 342 * @param mediaId media id to prepare 343 * @param extras optional extra bundle 344 * @see SessionCommand2#COMMAND_CODE_SESSION_PREPARE_FROM_MEDIA_ID 345 */ 346 public void onPrepareFromMediaId(@NonNull MediaSession2 session, 347 @NonNull ControllerInfo controller, @NonNull String mediaId, 348 @Nullable Bundle extras) { } 349 350 /** 351 * Called when a controller requested to prepare playback from a search query through 352 * {@link MediaController2#prepareFromSearch(String, Bundle)}. 353 * <p> 354 * An empty query indicates that the app may prepare any music. The implementation should 355 * attempt to make a smart choice about what to play. 356 * <p> 357 * The state of playback should be updated to {@link MediaPlayerBase#PLAYER_STATE_PAUSED} 358 * after the preparation is done. The playback of the prepared content should start in the 359 * later calls of {@link MediaSession2#play()}. 360 * <p> 361 * Override {@link #onPlayFromSearch} to handle requests for starting playback without 362 * preparation. 363 * 364 * @param session the session for this event 365 * @param controller controller information 366 * @param query query string. Can be empty to indicate any suggested media 367 * @param extras optional extra bundle 368 * @see SessionCommand2#COMMAND_CODE_SESSION_PREPARE_FROM_SEARCH 369 */ 370 public void onPrepareFromSearch(@NonNull MediaSession2 session, 371 @NonNull ControllerInfo controller, @NonNull String query, 372 @Nullable Bundle extras) { } 373 374 /** 375 * Called when a controller requested to prepare a specific media item represented by a URI 376 * through {@link MediaController2#prepareFromUri(Uri, Bundle)}. 377 * <p> 378 * During the preparation, a session should not hold audio focus in order to allow 379 * other sessions play seamlessly. The state of playback should be updated to 380 * {@link MediaPlayerBase#PLAYER_STATE_PAUSED} after the preparation is done. 381 * <p> 382 * The playback of the prepared content should start in the later calls of 383 * {@link MediaSession2#play()}. 384 * <p> 385 * Override {@link #onPlayFromUri} to handle requests for starting playback without 386 * preparation. 387 * 388 * @param session the session for this event 389 * @param controller controller information 390 * @param uri uri 391 * @param extras optional extra bundle 392 * @see SessionCommand2#COMMAND_CODE_SESSION_PREPARE_FROM_URI 393 */ 394 public void onPrepareFromUri(@NonNull MediaSession2 session, 395 @NonNull ControllerInfo controller, @NonNull Uri uri, @Nullable Bundle extras) { } 396 397 /** 398 * Called when a controller called {@link MediaController2#fastForward()} 399 * 400 * @param session the session for this event 401 */ 402 public void onFastForward(@NonNull MediaSession2 session) { } 403 404 /** 405 * Called when a controller called {@link MediaController2#rewind()} 406 * 407 * @param session the session for this event 408 */ 409 public void onRewind(@NonNull MediaSession2 session) { } 410 411 /** 412 * Called when the player's current playing item is changed 413 * <p> 414 * When it's called, you should invalidate previous playback information and wait for later 415 * callbacks. 416 * 417 * @param session the controller for this event 418 * @param player the player for this event 419 * @param item new item 420 */ 421 // TODO(jaewan): Use this (b/74316764) 422 public void onCurrentMediaItemChanged(@NonNull MediaSession2 session, 423 @NonNull MediaPlayerBase player, @NonNull MediaItem2 item) { } 424 425 /** 426 * Called when the player is <i>prepared</i>, i.e. it is ready to play the content 427 * referenced by the given data source. 428 * @param session the session for this event 429 * @param player the player for this event 430 * @param item the media item for which buffering is happening 431 */ 432 public void onMediaPrepared(@NonNull MediaSession2 session, @NonNull MediaPlayerBase player, 433 @NonNull MediaItem2 item) { } 434 435 /** 436 * Called to indicate that the state of the player has changed. 437 * See {@link MediaPlayerBase#getPlayerState()} for polling the player state. 438 * @param session the session for this event 439 * @param player the player for this event 440 * @param state the new state of the player. 441 */ 442 public void onPlayerStateChanged(@NonNull MediaSession2 session, 443 @NonNull MediaPlayerBase player, @PlayerState int state) { } 444 445 /** 446 * Called to report buffering events for a data source. 447 * 448 * @param session the session for this event 449 * @param player the player for this event 450 * @param item the media item for which buffering is happening. 451 * @param state the new buffering state. 452 */ 453 public void onBufferingStateChanged(@NonNull MediaSession2 session, 454 @NonNull MediaPlayerBase player, @NonNull MediaItem2 item, @BuffState int state) { } 455 456 /** 457 * Called to indicate that the playback speed has changed. 458 * @param session the session for this event 459 * @param player the player for this event 460 * @param speed the new playback speed. 461 */ 462 public void onPlaybackSpeedChanged(@NonNull MediaSession2 session, 463 @NonNull MediaPlayerBase player, float speed) { } 464 465 /** 466 * Called to indicate that {@link #seekTo(long)} is completed. 467 * 468 * @param session the session for this event. 469 * @param mpb the player that has completed seeking. 470 * @param position the previous seeking request. 471 * @see #seekTo(long) 472 */ 473 public void onSeekCompleted(@NonNull MediaSession2 session, @NonNull MediaPlayerBase mpb, 474 long position) { } 475 476 /** 477 * Called when a playlist is changed from the {@link MediaPlaylistAgent}. 478 * <p> 479 * This is called when the underlying agent has called 480 * {@link MediaPlaylistAgent.PlaylistEventCallback#onPlaylistChanged(MediaPlaylistAgent, 481 * List, MediaMetadata2)}. 482 * 483 * @param session the session for this event 484 * @param playlistAgent playlist agent for this event 485 * @param list new playlist 486 * @param metadata new metadata 487 */ 488 public void onPlaylistChanged(@NonNull MediaSession2 session, 489 @NonNull MediaPlaylistAgent playlistAgent, @NonNull List<MediaItem2> list, 490 @Nullable MediaMetadata2 metadata) { } 491 492 /** 493 * Called when a playlist metadata is changed. 494 * 495 * @param session the session for this event 496 * @param playlistAgent playlist agent for this event 497 * @param metadata new metadata 498 */ 499 public void onPlaylistMetadataChanged(@NonNull MediaSession2 session, 500 @NonNull MediaPlaylistAgent playlistAgent, @Nullable MediaMetadata2 metadata) { } 501 502 /** 503 * Called when the shuffle mode is changed. 504 * 505 * @param session the session for this event 506 * @param playlistAgent playlist agent for this event 507 * @param shuffleMode repeat mode 508 * @see MediaPlaylistAgent#SHUFFLE_MODE_NONE 509 * @see MediaPlaylistAgent#SHUFFLE_MODE_ALL 510 * @see MediaPlaylistAgent#SHUFFLE_MODE_GROUP 511 */ 512 public void onShuffleModeChanged(@NonNull MediaSession2 session, 513 @NonNull MediaPlaylistAgent playlistAgent, 514 @MediaPlaylistAgent.ShuffleMode int shuffleMode) { } 515 516 /** 517 * Called when the repeat mode is changed. 518 * 519 * @param session the session for this event 520 * @param playlistAgent playlist agent for this event 521 * @param repeatMode repeat mode 522 * @see MediaPlaylistAgent#REPEAT_MODE_NONE 523 * @see MediaPlaylistAgent#REPEAT_MODE_ONE 524 * @see MediaPlaylistAgent#REPEAT_MODE_ALL 525 * @see MediaPlaylistAgent#REPEAT_MODE_GROUP 526 */ 527 public void onRepeatModeChanged(@NonNull MediaSession2 session, 528 @NonNull MediaPlaylistAgent playlistAgent, 529 @MediaPlaylistAgent.RepeatMode int repeatMode) { } 530 } 531 532 /** 533 * Base builder class for MediaSession2 and its subclass. Any change in this class should be 534 * also applied to the subclasses {@link MediaSession2.Builder} and 535 * {@link MediaLibraryService2.MediaLibrarySession.Builder}. 536 * <p> 537 * APIs here should be package private, but should have documentations for developers. 538 * Otherwise, javadoc will generate documentation with the generic types such as follows. 539 * <pre>U extends BuilderBase<T, U, C> setSessionCallback(Executor executor, C callback)</pre> 540 * <p> 541 * This class is hidden to prevent from generating test stub, which fails with 542 * 'unexpected bound' because it tries to auto generate stub class as follows. 543 * <pre>abstract static class BuilderBase< 544 * T extends android.media.MediaSession2, 545 * U extends android.media.MediaSession2.BuilderBase< 546 * T, U, C extends android.media.MediaSession2.SessionCallback>, C></pre> 547 * @hide 548 */ 549 static abstract class BuilderBase 550 <T extends MediaSession2, U extends BuilderBase<T, U, C>, C extends SessionCallback> { 551 private final BuilderBaseProvider<T, C> mProvider; 552 553 BuilderBase(ProviderCreator<BuilderBase<T, U, C>, BuilderBaseProvider<T, C>> creator) { 554 mProvider = creator.createProvider(this); 555 } 556 557 /** 558 * Sets the underlying {@link MediaPlayerBase} for this session to dispatch incoming event 559 * to. 560 * 561 * @param player a {@link MediaPlayerBase} that handles actual media playback in your app. 562 */ 563 @NonNull U setPlayer(@NonNull MediaPlayerBase player) { 564 mProvider.setPlayer_impl(player); 565 return (U) this; 566 } 567 568 /** 569 * Sets the {@link MediaPlaylistAgent} for this session to manages playlist of the 570 * underlying {@link MediaPlayerBase}. The playlist agent should manage 571 * {@link MediaPlayerBase} for calling {@link MediaPlayerBase#setNextDataSources(List)}. 572 * <p> 573 * If the {@link MediaPlaylistAgent} isn't set, session will create the default playlist 574 * agent. 575 * 576 * @param playlistAgent a {@link MediaPlaylistAgent} that manages playlist of the 577 * {@code player} 578 */ 579 U setPlaylistAgent(@NonNull MediaPlaylistAgent playlistAgent) { 580 mProvider.setPlaylistAgent_impl(playlistAgent); 581 return (U) this; 582 } 583 584 /** 585 * Sets the {@link VolumeProvider2} for this session to handle volume events. If not set, 586 * system will adjust the appropriate stream volume for this session's player. 587 * 588 * @param volumeProvider The provider that will receive volume button events. 589 */ 590 @NonNull U setVolumeProvider(@Nullable VolumeProvider2 volumeProvider) { 591 mProvider.setVolumeProvider_impl(volumeProvider); 592 return (U) this; 593 } 594 595 /** 596 * Set an intent for launching UI for this Session. This can be used as a 597 * quick link to an ongoing media screen. The intent should be for an 598 * activity that may be started using {@link Context#startActivity(Intent)}. 599 * 600 * @param pi The intent to launch to show UI for this session. 601 */ 602 @NonNull U setSessionActivity(@Nullable PendingIntent pi) { 603 mProvider.setSessionActivity_impl(pi); 604 return (U) this; 605 } 606 607 /** 608 * Set ID of the session. If it's not set, an empty string with used to create a session. 609 * <p> 610 * Use this if and only if your app supports multiple playback at the same time and also 611 * wants to provide external apps to have finer controls of them. 612 * 613 * @param id id of the session. Must be unique per package. 614 * @throws IllegalArgumentException if id is {@code null} 615 * @return 616 */ 617 @NonNull U setId(@NonNull String id) { 618 mProvider.setId_impl(id); 619 return (U) this; 620 } 621 622 /** 623 * Set callback for the session. 624 * 625 * @param executor callback executor 626 * @param callback session callback. 627 * @return 628 */ 629 @NonNull U setSessionCallback(@NonNull @CallbackExecutor Executor executor, 630 @NonNull C callback) { 631 mProvider.setSessionCallback_impl(executor, callback); 632 return (U) this; 633 } 634 635 /** 636 * Build {@link MediaSession2}. 637 * 638 * @return a new session 639 * @throws IllegalStateException if the session with the same id is already exists for the 640 * package. 641 */ 642 @NonNull T build() { 643 return mProvider.build_impl(); 644 } 645 } 646 647 /** 648 * Builder for {@link MediaSession2}. 649 * <p> 650 * Any incoming event from the {@link MediaController2} will be handled on the thread 651 * that created session with the {@link Builder#build()}. 652 */ 653 // Override all methods just to show them with the type instead of generics in Javadoc. 654 // This workarounds javadoc issue described in the MediaSession2.BuilderBase. 655 public static final class Builder extends BuilderBase<MediaSession2, Builder, SessionCallback> { 656 public Builder(Context context) { 657 super((instance) -> ApiLoader.getProvider().createMediaSession2Builder( 658 context, (Builder) instance)); 659 } 660 661 @Override 662 public @NonNull Builder setPlayer(@NonNull MediaPlayerBase player) { 663 return super.setPlayer(player); 664 } 665 666 @Override 667 public Builder setPlaylistAgent(@NonNull MediaPlaylistAgent playlistAgent) { 668 return super.setPlaylistAgent(playlistAgent); 669 } 670 671 @Override 672 public @NonNull Builder setVolumeProvider(@Nullable VolumeProvider2 volumeProvider) { 673 return super.setVolumeProvider(volumeProvider); 674 } 675 676 @Override 677 public @NonNull Builder setSessionActivity(@Nullable PendingIntent pi) { 678 return super.setSessionActivity(pi); 679 } 680 681 @Override 682 public @NonNull Builder setId(@NonNull String id) { 683 return super.setId(id); 684 } 685 686 @Override 687 public @NonNull Builder setSessionCallback(@NonNull Executor executor, 688 @Nullable SessionCallback callback) { 689 return super.setSessionCallback(executor, callback); 690 } 691 692 @Override 693 public @NonNull MediaSession2 build() { 694 return super.build(); 695 } 696 } 697 698 /** 699 * Information of a controller. 700 */ 701 public static final class ControllerInfo { 702 private final ControllerInfoProvider mProvider; 703 704 /** 705 * @hide 706 */ 707 public ControllerInfo(@NonNull Context context, int uid, int pid, 708 @NonNull String packageName, @NonNull IInterface callback) { 709 mProvider = ApiLoader.getProvider().createMediaSession2ControllerInfo( 710 context, this, uid, pid, packageName, callback); 711 } 712 713 /** 714 * @return package name of the controller 715 */ 716 public @NonNull String getPackageName() { 717 return mProvider.getPackageName_impl(); 718 } 719 720 /** 721 * @return uid of the controller 722 */ 723 public int getUid() { 724 return mProvider.getUid_impl(); 725 } 726 727 /** 728 * Return if the controller has granted {@code android.permission.MEDIA_CONTENT_CONTROL} or 729 * has a enabled notification listener so can be trusted to accept connection and incoming 730 * command request. 731 * 732 * @return {@code true} if the controller is trusted. 733 */ 734 public boolean isTrusted() { 735 return mProvider.isTrusted_impl(); 736 } 737 738 /** 739 * @hide 740 */ 741 public @NonNull ControllerInfoProvider getProvider() { 742 return mProvider; 743 } 744 745 @Override 746 public int hashCode() { 747 return mProvider.hashCode_impl(); 748 } 749 750 @Override 751 public boolean equals(Object obj) { 752 return mProvider.equals_impl(obj); 753 } 754 755 @Override 756 public String toString() { 757 return mProvider.toString_impl(); 758 } 759 } 760 761 /** 762 * Button for a {@link SessionCommand2} that will be shown by the controller. 763 * <p> 764 * It's up to the controller's decision to respect or ignore this customization request. 765 */ 766 public static final class CommandButton { 767 private final CommandButtonProvider mProvider; 768 769 /** 770 * @hide 771 */ 772 public CommandButton(CommandButtonProvider provider) { 773 mProvider = provider; 774 } 775 776 /** 777 * Get command associated with this button. Can be {@code null} if the button isn't enabled 778 * and only providing placeholder. 779 * 780 * @return command or {@code null} 781 */ 782 public @Nullable 783 SessionCommand2 getCommand() { 784 return mProvider.getCommand_impl(); 785 } 786 787 /** 788 * Resource id of the button in this package. Can be {@code 0} if the command is predefined 789 * and custom icon isn't needed. 790 * 791 * @return resource id of the icon. Can be {@code 0}. 792 */ 793 public int getIconResId() { 794 return mProvider.getIconResId_impl(); 795 } 796 797 /** 798 * Display name of the button. Can be {@code null} or empty if the command is predefined 799 * and custom name isn't needed. 800 * 801 * @return custom display name. Can be {@code null} or empty. 802 */ 803 public @Nullable String getDisplayName() { 804 return mProvider.getDisplayName_impl(); 805 } 806 807 /** 808 * Extra information of the button. It's private information between session and controller. 809 * 810 * @return 811 */ 812 public @Nullable Bundle getExtras() { 813 return mProvider.getExtras_impl(); 814 } 815 816 /** 817 * Return whether it's enabled 818 * 819 * @return {@code true} if enabled. {@code false} otherwise. 820 */ 821 public boolean isEnabled() { 822 return mProvider.isEnabled_impl(); 823 } 824 825 /** 826 * @hide 827 */ 828 public @NonNull CommandButtonProvider getProvider() { 829 return mProvider; 830 } 831 832 /** 833 * Builder for {@link CommandButton}. 834 */ 835 public static final class Builder { 836 private final CommandButtonProvider.BuilderProvider mProvider; 837 838 public Builder() { 839 mProvider = ApiLoader.getProvider().createMediaSession2CommandButtonBuilder(this); 840 } 841 842 public @NonNull Builder setCommand(@Nullable SessionCommand2 command) { 843 return mProvider.setCommand_impl(command); 844 } 845 846 public @NonNull Builder setIconResId(int resId) { 847 return mProvider.setIconResId_impl(resId); 848 } 849 850 public @NonNull Builder setDisplayName(@Nullable String displayName) { 851 return mProvider.setDisplayName_impl(displayName); 852 } 853 854 public @NonNull Builder setEnabled(boolean enabled) { 855 return mProvider.setEnabled_impl(enabled); 856 } 857 858 public @NonNull Builder setExtras(@Nullable Bundle extras) { 859 return mProvider.setExtras_impl(extras); 860 } 861 862 public @NonNull CommandButton build() { 863 return mProvider.build_impl(); 864 } 865 } 866 } 867 868 /** 869 * Constructor is hidden and apps can only instantiate indirectly through {@link Builder}. 870 * <p> 871 * This intended behavior and here's the reasons. 872 * 1. Prevent multiple sessions with the same tag in a media app. 873 * Whenever it happens only one session was properly setup and others were all dummies. 874 * Android framework couldn't find the right session to dispatch media key event. 875 * 2. Simplify session's lifecycle. 876 * {@link android.media.session.MediaSession} is available after all of 877 * {@link android.media.session.MediaSession#setFlags(int)}, 878 * {@link android.media.session.MediaSession#setCallback( 879 * android.media.session.MediaSession.Callback)}, 880 * and {@link android.media.session.MediaSession#setActive(boolean)}. 881 * It was common for an app to omit one, so framework had to add heuristics to figure out 882 * which should be the highest priority for handling media key event. 883 * @hide 884 */ 885 public MediaSession2(MediaSession2Provider provider) { 886 super(); 887 mProvider = provider; 888 } 889 890 /** 891 * @hide 892 */ 893 public @NonNull MediaSession2Provider getProvider() { 894 return mProvider; 895 } 896 897 /** 898 * Sets the underlying {@link MediaPlayerBase} and {@link MediaPlaylistAgent} for this session 899 * to dispatch incoming event to. 900 * <p> 901 * When a {@link MediaPlaylistAgent} is specified here, the playlist agent should manage 902 * {@link MediaPlayerBase} for calling {@link MediaPlayerBase#setNextDataSources(List)}. 903 * <p> 904 * If the {@link MediaPlaylistAgent} isn't set, session will recreate the default playlist 905 * agent. 906 * 907 * @param player a {@link MediaPlayerBase} that handles actual media playback in your app 908 * @param playlistAgent a {@link MediaPlaylistAgent} that manages playlist of the {@code player} 909 * @param volumeProvider a {@link VolumeProvider2}. If {@code null}, system will adjust the 910 * appropriate stream volume for this session's player. 911 */ 912 public void updatePlayer(@NonNull MediaPlayerBase player, 913 @Nullable MediaPlaylistAgent playlistAgent, @Nullable VolumeProvider2 volumeProvider) { 914 mProvider.updatePlayer_impl(player, playlistAgent, volumeProvider); 915 } 916 917 @Override 918 public void close() { 919 mProvider.close_impl(); 920 } 921 922 /** 923 * @return player 924 */ 925 public @NonNull MediaPlayerBase getPlayer() { 926 return mProvider.getPlayer_impl(); 927 } 928 929 /** 930 * @return playlist agent 931 */ 932 public @NonNull MediaPlaylistAgent getPlaylistAgent() { 933 return mProvider.getPlaylistAgent_impl(); 934 } 935 936 /** 937 * @return volume provider 938 */ 939 public @Nullable VolumeProvider2 getVolumeProvider() { 940 return mProvider.getVolumeProvider_impl(); 941 } 942 943 /** 944 * Returns the {@link SessionToken2} for creating {@link MediaController2}. 945 */ 946 public @NonNull 947 SessionToken2 getToken() { 948 return mProvider.getToken_impl(); 949 } 950 951 public @NonNull List<ControllerInfo> getConnectedControllers() { 952 return mProvider.getConnectedControllers_impl(); 953 } 954 955 /** 956 * Set the {@link AudioFocusRequest} to obtain the audio focus 957 * 958 * @param afr the full request parameters 959 */ 960 public void setAudioFocusRequest(@Nullable AudioFocusRequest afr) { 961 // TODO(jaewan): implement this (b/72529899) 962 // mProvider.setAudioFocusRequest_impl(focusGain); 963 } 964 965 /** 966 * Sets ordered list of {@link CommandButton} for controllers to build UI with it. 967 * <p> 968 * It's up to controller's decision how to represent the layout in its own UI. 969 * Here's the same way 970 * (layout[i] means a CommandButton at index i in the given list) 971 * For 5 icons row 972 * layout[3] layout[1] layout[0] layout[2] layout[4] 973 * For 3 icons row 974 * layout[1] layout[0] layout[2] 975 * For 5 icons row with overflow icon (can show +5 extra buttons with overflow button) 976 * expanded row: layout[5] layout[6] layout[7] layout[8] layout[9] 977 * main row: layout[3] layout[1] layout[0] layout[2] layout[4] 978 * <p> 979 * This API can be called in the {@link SessionCallback#onConnect( 980 * MediaSession2, ControllerInfo)}. 981 * 982 * @param controller controller to specify layout. 983 * @param layout ordered list of layout. 984 */ 985 public void setCustomLayout(@NonNull ControllerInfo controller, 986 @NonNull List<CommandButton> layout) { 987 mProvider.setCustomLayout_impl(controller, layout); 988 } 989 990 /** 991 * Set the new allowed command group for the controller 992 * 993 * @param controller controller to change allowed commands 994 * @param commands new allowed commands 995 */ 996 public void setAllowedCommands(@NonNull ControllerInfo controller, 997 @NonNull SessionCommandGroup2 commands) { 998 mProvider.setAllowedCommands_impl(controller, commands); 999 } 1000 1001 /** 1002 * Send custom command to all connected controllers. 1003 * 1004 * @param command a command 1005 * @param args optional argument 1006 */ 1007 public void sendCustomCommand(@NonNull SessionCommand2 command, @Nullable Bundle args) { 1008 mProvider.sendCustomCommand_impl(command, args); 1009 } 1010 1011 /** 1012 * Send custom command to a specific controller. 1013 * 1014 * @param command a command 1015 * @param args optional argument 1016 * @param receiver result receiver for the session 1017 */ 1018 public void sendCustomCommand(@NonNull ControllerInfo controller, 1019 @NonNull SessionCommand2 command, @Nullable Bundle args, 1020 @Nullable ResultReceiver receiver) { 1021 // Equivalent to the MediaController.sendCustomCommand(Action action, ResultReceiver r); 1022 mProvider.sendCustomCommand_impl(controller, command, args, receiver); 1023 } 1024 1025 /** 1026 * Play playback 1027 * <p> 1028 * This calls {@link MediaPlayerBase#play()}. 1029 */ 1030 public void play() { 1031 mProvider.play_impl(); 1032 } 1033 1034 /** 1035 * Pause playback. 1036 * <p> 1037 * This calls {@link MediaPlayerBase#pause()}. 1038 */ 1039 public void pause() { 1040 mProvider.pause_impl(); 1041 } 1042 1043 /** 1044 * Stop playback, and reset the player to the initial state. 1045 * <p> 1046 * This calls {@link MediaPlayerBase#reset()}. 1047 */ 1048 public void stop() { 1049 mProvider.stop_impl(); 1050 } 1051 1052 /** 1053 * Request that the player prepare its playback. In other words, other sessions can continue 1054 * to play during the preparation of this session. This method can be used to speed up the 1055 * start of the playback. Once the preparation is done, the session will change its playback 1056 * state to {@link MediaPlayerBase#PLAYER_STATE_PAUSED}. Afterwards, {@link #play} can be called 1057 * to start playback. 1058 * <p> 1059 * This calls {@link MediaPlayerBase#reset()}. 1060 */ 1061 public void prepare() { 1062 mProvider.prepare_impl(); 1063 } 1064 1065 /** 1066 * Move to a new location in the media stream. 1067 * 1068 * @param pos Position to move to, in milliseconds. 1069 */ 1070 public void seekTo(long pos) { 1071 mProvider.seekTo_impl(pos); 1072 } 1073 1074 /** 1075 * @hide 1076 */ 1077 public void skipForward() { 1078 // To match with KEYCODE_MEDIA_SKIP_FORWARD 1079 } 1080 1081 /** 1082 * @hide 1083 */ 1084 public void skipBackward() { 1085 // To match with KEYCODE_MEDIA_SKIP_BACKWARD 1086 } 1087 1088 /** 1089 * Notify errors to the connected controllers 1090 * 1091 * @param errorCode error code 1092 * @param extras extras 1093 */ 1094 public void notifyError(@ErrorCode int errorCode, @Nullable Bundle extras) { 1095 mProvider.notifyError_impl(errorCode, extras); 1096 } 1097 1098 /** 1099 * Gets the current player state. 1100 * 1101 * @return the current player state 1102 */ 1103 public @PlayerState int getPlayerState() { 1104 return mProvider.getPlayerState_impl(); 1105 } 1106 1107 /** 1108 * Gets the current position. 1109 * 1110 * @return the current playback position in ms, or {@link MediaPlayerBase#UNKNOWN_TIME} if 1111 * unknown. 1112 */ 1113 public long getCurrentPosition() { 1114 return mProvider.getCurrentPosition_impl(); 1115 } 1116 1117 /** 1118 * Gets the buffered position, or {@link MediaPlayerBase#UNKNOWN_TIME} if unknown. 1119 * 1120 * @return the buffered position in ms, or {@link MediaPlayerBase#UNKNOWN_TIME}. 1121 */ 1122 public long getBufferedPosition() { 1123 return mProvider.getBufferedPosition_impl(); 1124 } 1125 1126 /** 1127 * Gets the current buffering state of the player. 1128 * During buffering, see {@link #getBufferedPosition()} for the quantifying the amount already 1129 * buffered. 1130 * 1131 * @return the buffering state. 1132 */ 1133 public @BuffState int getBufferingState() { 1134 // TODO(jaewan): Implement this 1135 return BUFFERING_STATE_UNKNOWN; 1136 } 1137 1138 /** 1139 * Get the playback speed. 1140 * 1141 * @return speed 1142 */ 1143 public float getPlaybackSpeed() { 1144 // TODO(jaewan): implement this (b/74093080) 1145 return -1; 1146 } 1147 1148 /** 1149 * Set the playback speed. 1150 */ 1151 public void setPlaybackSpeed(float speed) { 1152 // TODO(jaewan): implement this (b/74093080) 1153 } 1154 1155 /** 1156 * Sets the data source missing helper. Helper will be used to provide default implementation of 1157 * {@link MediaPlaylistAgent} when it isn't set by developer. 1158 * <p> 1159 * Default implementation of the {@link MediaPlaylistAgent} will call helper when a 1160 * {@link MediaItem2} in the playlist doesn't have a {@link DataSourceDesc}. This may happen 1161 * when 1162 * <ul> 1163 * <li>{@link MediaItem2} specified by {@link #setPlaylist(List, MediaMetadata2)} doesn't 1164 * have {@link DataSourceDesc}</li> 1165 * <li>{@link MediaController2#addPlaylistItem(int, MediaItem2)} is called and accepted 1166 * by {@link SessionCallback#onCommandRequest( 1167 * MediaSession2, ControllerInfo, SessionCommand2)}. 1168 * In that case, an item would be added automatically without the data source.</li> 1169 * </ul> 1170 * <p> 1171 * If it's not set, playback wouldn't happen for the item without data source descriptor. 1172 * <p> 1173 * The helper will be run on the executor that was specified by 1174 * {@link Builder#setSessionCallback(Executor, SessionCallback)}. 1175 * 1176 * @param helper a data source missing helper. 1177 * @throws IllegalStateException when the helper is set when the playlist agent is set 1178 * @see #setPlaylist(List, MediaMetadata2) 1179 * @see SessionCallback#onCommandRequest(MediaSession2, ControllerInfo, SessionCommand2) 1180 * @see SessionCommand2#COMMAND_CODE_PLAYLIST_ADD_ITEM 1181 * @see SessionCommand2#COMMAND_CODE_PLAYLIST_REPLACE_ITEM 1182 */ 1183 public void setOnDataSourceMissingHelper(@NonNull OnDataSourceMissingHelper helper) { 1184 mProvider.setOnDataSourceMissingHelper_impl(helper); 1185 } 1186 1187 /** 1188 * Clears the data source missing helper. 1189 * 1190 * @see #setOnDataSourceMissingHelper(OnDataSourceMissingHelper) 1191 */ 1192 public void clearOnDataSourceMissingHelper() { 1193 mProvider.clearOnDataSourceMissingHelper_impl(); 1194 } 1195 1196 /** 1197 * Returns the playlist from the {@link MediaPlaylistAgent}. 1198 * <p> 1199 * This list may differ with the list that was specified with 1200 * {@link #setPlaylist(List, MediaMetadata2)} depending on the {@link MediaPlaylistAgent} 1201 * implementation. Use media items returned here for other playlist agent APIs such as 1202 * {@link MediaPlaylistAgent#skipToPlaylistItem(MediaItem2)}. 1203 * 1204 * @return playlist 1205 * @see MediaPlaylistAgent#getPlaylist() 1206 * @see SessionCallback#onPlaylistChanged( 1207 * MediaSession2, MediaPlaylistAgent, List, MediaMetadata2) 1208 */ 1209 public List<MediaItem2> getPlaylist() { 1210 return mProvider.getPlaylist_impl(); 1211 } 1212 1213 /** 1214 * Sets a list of {@link MediaItem2} to the {@link MediaPlaylistAgent}. Ensure uniqueness of 1215 * each {@link MediaItem2} in the playlist so the session can uniquely identity individual 1216 * items. 1217 * <p> 1218 * This may be an asynchronous call, and {@link MediaPlaylistAgent} may keep the copy of the 1219 * list. Wait for {@link SessionCallback#onPlaylistChanged(MediaSession2, MediaPlaylistAgent, 1220 * List, MediaMetadata2)} to know the operation finishes. 1221 * <p> 1222 * You may specify a {@link MediaItem2} without {@link DataSourceDesc}. In that case, 1223 * {@link MediaPlaylistAgent} has responsibility to dynamically query {@link DataSourceDesc} 1224 * when such media item is ready for preparation or play. Default implementation needs 1225 * {@link OnDataSourceMissingHelper} for such case. 1226 * 1227 * @param list A list of {@link MediaItem2} objects to set as a play list. 1228 * @throws IllegalArgumentException if given list is {@code null}, or has duplicated media 1229 * items. 1230 * @see MediaPlaylistAgent#setPlaylist(List, MediaMetadata2) 1231 * @see SessionCallback#onPlaylistChanged( 1232 * MediaSession2, MediaPlaylistAgent, List, MediaMetadata2) 1233 * @see #setOnDataSourceMissingHelper 1234 */ 1235 public void setPlaylist(@NonNull List<MediaItem2> list, @Nullable MediaMetadata2 metadata) { 1236 mProvider.setPlaylist_impl(list, metadata); 1237 } 1238 1239 /** 1240 * Skips to the item in the playlist. 1241 * <p> 1242 * This calls {@link MediaPlaylistAgent#skipToPlaylistItem(MediaItem2)} and the behavior depends 1243 * on the playlist agent implementation, especially with the shuffle/repeat mode. 1244 * 1245 * @param item The item in the playlist you want to play 1246 * @see #getShuffleMode() 1247 * @see #getRepeatMode() 1248 */ 1249 public void skipToPlaylistItem(@NonNull MediaItem2 item) { 1250 mProvider.skipToPlaylistItem_impl(item); 1251 } 1252 1253 /** 1254 * Skips to the previous item. 1255 * <p> 1256 * This calls {@link MediaPlaylistAgent#skipToPreviousItem()} and the behavior depends on the 1257 * playlist agent implementation, especially with the shuffle/repeat mode. 1258 * 1259 * @see #getShuffleMode() 1260 * @see #getRepeatMode() 1261 **/ 1262 public void skipToPreviousItem() { 1263 mProvider.skipToPreviousItem_impl(); 1264 } 1265 1266 /** 1267 * Skips to the next item. 1268 * <p> 1269 * This calls {@link MediaPlaylistAgent#skipToNextItem()} and the behavior depends on the 1270 * playlist agent implementation, especially with the shuffle/repeat mode. 1271 * 1272 * @see #getShuffleMode() 1273 * @see #getRepeatMode() 1274 */ 1275 public void skipToNextItem() { 1276 mProvider.skipToNextItem_impl(); 1277 } 1278 1279 /** 1280 * Gets the playlist metadata from the {@link MediaPlaylistAgent}. 1281 * 1282 * @return the playlist metadata 1283 */ 1284 public MediaMetadata2 getPlaylistMetadata() { 1285 return mProvider.getPlaylistMetadata_impl(); 1286 } 1287 1288 /** 1289 * Adds the media item to the playlist at position index. Index equals or greater than 1290 * the current playlist size will add the item at the end of the playlist. 1291 * <p> 1292 * This will not change the currently playing media item. 1293 * If index is less than or equal to the current index of the play list, 1294 * the current index of the play list will be incremented correspondingly. 1295 * 1296 * @param index the index you want to add 1297 * @param item the media item you want to add 1298 */ 1299 public void addPlaylistItem(int index, @NonNull MediaItem2 item) { 1300 mProvider.addPlaylistItem_impl(index, item); 1301 } 1302 1303 /** 1304 * Removes the media item in the playlist. 1305 * <p> 1306 * If the item is the currently playing item of the playlist, current playback 1307 * will be stopped and playback moves to next source in the list. 1308 * 1309 * @param item the media item you want to add 1310 */ 1311 public void removePlaylistItem(@NonNull MediaItem2 item) { 1312 mProvider.removePlaylistItem_impl(item); 1313 } 1314 1315 /** 1316 * Replaces the media item at index in the playlist. This can be also used to update metadata of 1317 * an item. 1318 * 1319 * @param index the index of the item to replace 1320 * @param item the new item 1321 */ 1322 public void replacePlaylistItem(int index, @NonNull MediaItem2 item) { 1323 mProvider.replacePlaylistItem_impl(index, item); 1324 } 1325 1326 /** 1327 * Return currently playing media item. 1328 * 1329 * @return currently playing media item 1330 */ 1331 public MediaItem2 getCurrentMediaItem() { 1332 // TODO(jaewan): Rename provider, and implement (b/74316764) 1333 return mProvider.getCurrentPlaylistItem_impl(); 1334 } 1335 1336 /** 1337 * Updates the playlist metadata to the {@link MediaPlaylistAgent}. 1338 * 1339 * @param metadata metadata of the playlist 1340 */ 1341 public void updatePlaylistMetadata(@Nullable MediaMetadata2 metadata) { 1342 mProvider.updatePlaylistMetadata_impl(metadata); 1343 } 1344 1345 /** 1346 * Gets the repeat mode from the {@link MediaPlaylistAgent}. 1347 * 1348 * @return repeat mode 1349 * @see MediaPlaylistAgent#REPEAT_MODE_NONE 1350 * @see MediaPlaylistAgent#REPEAT_MODE_ONE 1351 * @see MediaPlaylistAgent#REPEAT_MODE_ALL 1352 * @see MediaPlaylistAgent#REPEAT_MODE_GROUP 1353 */ 1354 public @RepeatMode int getRepeatMode() { 1355 return mProvider.getRepeatMode_impl(); 1356 } 1357 1358 /** 1359 * Sets the repeat mode to the {@link MediaPlaylistAgent}. 1360 * 1361 * @param repeatMode repeat mode 1362 * @see MediaPlaylistAgent#REPEAT_MODE_NONE 1363 * @see MediaPlaylistAgent#REPEAT_MODE_ONE 1364 * @see MediaPlaylistAgent#REPEAT_MODE_ALL 1365 * @see MediaPlaylistAgent#REPEAT_MODE_GROUP 1366 */ 1367 public void setRepeatMode(@RepeatMode int repeatMode) { 1368 mProvider.setRepeatMode_impl(repeatMode); 1369 } 1370 1371 /** 1372 * Gets the shuffle mode from the {@link MediaPlaylistAgent}. 1373 * 1374 * @return The shuffle mode 1375 * @see MediaPlaylistAgent#SHUFFLE_MODE_NONE 1376 * @see MediaPlaylistAgent#SHUFFLE_MODE_ALL 1377 * @see MediaPlaylistAgent#SHUFFLE_MODE_GROUP 1378 */ 1379 public @ShuffleMode int getShuffleMode() { 1380 return mProvider.getShuffleMode_impl(); 1381 } 1382 1383 /** 1384 * Sets the shuffle mode to the {@link MediaPlaylistAgent}. 1385 * 1386 * @param shuffleMode The shuffle mode 1387 * @see MediaPlaylistAgent#SHUFFLE_MODE_NONE 1388 * @see MediaPlaylistAgent#SHUFFLE_MODE_ALL 1389 * @see MediaPlaylistAgent#SHUFFLE_MODE_GROUP 1390 */ 1391 public void setShuffleMode(@ShuffleMode int shuffleMode) { 1392 mProvider.setShuffleMode_impl(shuffleMode); 1393 } 1394 } 1395