MediaSession2Test.java revision 3a151f1283d08b40c12e4a17903ba421f23c4342
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 17package androidx.media; 18 19import static android.media.AudioAttributes.CONTENT_TYPE_MUSIC; 20 21import static androidx.media.VolumeProviderCompat.VOLUME_CONTROL_ABSOLUTE; 22import static androidx.media.VolumeProviderCompat.VOLUME_CONTROL_FIXED; 23 24import static org.junit.Assert.assertEquals; 25import static org.junit.Assert.assertFalse; 26import static org.junit.Assert.assertNotEquals; 27import static org.junit.Assert.assertNotNull; 28import static org.junit.Assert.assertNull; 29import static org.junit.Assert.assertSame; 30import static org.junit.Assert.assertTrue; 31import static org.junit.Assert.fail; 32 33import android.content.Context; 34import android.media.AudioManager; 35import android.os.Build; 36import android.os.Bundle; 37import android.os.Process; 38import android.os.ResultReceiver; 39import android.support.test.filters.SdkSuppress; 40import android.support.test.filters.SmallTest; 41import android.support.test.runner.AndroidJUnit4; 42 43import androidx.annotation.NonNull; 44import androidx.annotation.Nullable; 45import androidx.media.MediaController2.ControllerCallback; 46import androidx.media.MediaController2.PlaybackInfo; 47import androidx.media.MediaSession2.CommandButton; 48import androidx.media.MediaSession2.ControllerInfo; 49import androidx.media.MediaSession2.SessionCallback; 50 51import junit.framework.Assert; 52 53import org.junit.After; 54import org.junit.Before; 55import org.junit.Ignore; 56import org.junit.Test; 57import org.junit.runner.RunWith; 58 59import java.util.ArrayList; 60import java.util.List; 61import java.util.Set; 62import java.util.concurrent.CountDownLatch; 63import java.util.concurrent.TimeUnit; 64 65/** 66 * Tests {@link MediaSession2}. 67 */ 68@SdkSuppress(minSdkVersion = Build.VERSION_CODES.KITKAT) 69@RunWith(AndroidJUnit4.class) 70@SmallTest 71public class MediaSession2Test extends MediaSession2TestBase { 72 private static final String TAG = "MediaSession2Test"; 73 74 private MediaSession2 mSession; 75 private MockPlayer mPlayer; 76 private MockPlaylistAgent mMockAgent; 77 78 @Before 79 @Override 80 public void setUp() throws Exception { 81 super.setUp(); 82 mPlayer = new MockPlayer(0); 83 mMockAgent = new MockPlaylistAgent(); 84 85 mSession = new MediaSession2.Builder(mContext) 86 .setPlayer(mPlayer) 87 .setPlaylistAgent(mMockAgent) 88 .setSessionCallback(sHandlerExecutor, new SessionCallback() { 89 @Override 90 public SessionCommandGroup2 onConnect(MediaSession2 session, 91 ControllerInfo controller) { 92 if (Process.myUid() == controller.getUid()) { 93 return super.onConnect(session, controller); 94 } 95 return null; 96 } 97 }).build(); 98 } 99 100 @After 101 @Override 102 public void cleanUp() throws Exception { 103 super.cleanUp(); 104 mSession.close(); 105 } 106 107 @Test 108 public void testBuilder() { 109 prepareLooper(); 110 MediaSession2.Builder builder = new MediaSession2.Builder(mContext); 111 try { 112 builder.setPlayer(null); 113 fail("null player shouldn't be allowed"); 114 } catch (IllegalArgumentException e) { 115 // expected. pass-through 116 } 117 try { 118 builder.setId(null); 119 fail("null id shouldn't be allowed"); 120 } catch (IllegalArgumentException e) { 121 // expected. pass-through 122 } 123 } 124 125 @Test 126 public void testPlayerStateChange() throws Exception { 127 prepareLooper(); 128 final int targetState = MediaPlayerBase.PLAYER_STATE_PLAYING; 129 final CountDownLatch latchForSessionCallback = new CountDownLatch(1); 130 sHandler.postAndSync(new Runnable() { 131 @Override 132 public void run() { 133 mSession.close(); 134 mSession = new MediaSession2.Builder(mContext) 135 .setPlayer(mPlayer) 136 .setSessionCallback(sHandlerExecutor, new SessionCallback() { 137 @Override 138 public void onPlayerStateChanged(MediaSession2 session, 139 MediaPlayerBase player, int state) { 140 assertEquals(targetState, state); 141 latchForSessionCallback.countDown(); 142 } 143 }).build(); 144 } 145 }); 146 147 final CountDownLatch latchForControllerCallback = new CountDownLatch(1); 148 final MediaController2 controller = 149 createController(mSession.getToken(), true, new ControllerCallback() { 150 @Override 151 public void onPlayerStateChanged(MediaController2 controllerOut, int state) { 152 assertEquals(targetState, state); 153 latchForControllerCallback.countDown(); 154 } 155 }); 156 157 mPlayer.notifyPlaybackState(MediaPlayerBase.PLAYER_STATE_PLAYING); 158 assertTrue(latchForSessionCallback.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS)); 159 assertTrue(latchForControllerCallback.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS)); 160 assertEquals(targetState, controller.getPlayerState()); 161 } 162 163 @Test 164 public void testCurrentDataSourceChanged() throws Exception { 165 prepareLooper(); 166 final int listSize = 5; 167 final List<MediaItem2> list = TestUtils.createPlaylist(listSize); 168 mMockAgent.setPlaylist(list, null); 169 170 final MediaItem2 currentItem = list.get(3); 171 final CountDownLatch latchForSessionCallback = new CountDownLatch(1); 172 try (MediaSession2 session = new MediaSession2.Builder(mContext) 173 .setPlayer(mPlayer) 174 .setPlaylistAgent(mMockAgent) 175 .setId("testCurrentDataSourceChanged") 176 .setSessionCallback(sHandlerExecutor, new SessionCallback() { 177 @Override 178 public void onCurrentMediaItemChanged(MediaSession2 session, 179 MediaPlayerBase player, MediaItem2 itemOut) { 180 assertSame(currentItem, itemOut); 181 latchForSessionCallback.countDown(); 182 } 183 }).build()) { 184 185 final CountDownLatch latchForControllerCallback = new CountDownLatch(1); 186 final MediaController2 controller = 187 createController(mSession.getToken(), true, new ControllerCallback() { 188 @Override 189 public void onCurrentMediaItemChanged(MediaController2 controller, 190 MediaItem2 item) { 191 assertEquals(currentItem, item); 192 latchForControllerCallback.countDown(); 193 } 194 }); 195 196 mPlayer.notifyCurrentDataSourceChanged(currentItem.getDataSourceDesc()); 197 assertTrue(latchForSessionCallback.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS)); 198 assertTrue(latchForControllerCallback.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS)); 199 assertEquals(currentItem, controller.getCurrentMediaItem()); 200 } 201 } 202 203 @Test 204 public void testMediaPrepared() throws Exception { 205 prepareLooper(); 206 final int listSize = 5; 207 final List<MediaItem2> list = TestUtils.createPlaylist(listSize); 208 mMockAgent.setPlaylist(list, null); 209 210 final MediaItem2 currentItem = list.get(3); 211 212 final CountDownLatch latchForSessionCallback = new CountDownLatch(1); 213 try (MediaSession2 session = new MediaSession2.Builder(mContext) 214 .setPlayer(mPlayer) 215 .setPlaylistAgent(mMockAgent) 216 .setId("testMediaPrepared") 217 .setSessionCallback(sHandlerExecutor, new SessionCallback() { 218 @Override 219 public void onMediaPrepared(MediaSession2 session, MediaPlayerBase player, 220 MediaItem2 itemOut) { 221 assertSame(currentItem, itemOut); 222 latchForSessionCallback.countDown(); 223 } 224 }).build()) { 225 226 mPlayer.notifyMediaPrepared(currentItem.getDataSourceDesc()); 227 assertTrue(latchForSessionCallback.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS)); 228 // TODO(jaewan): Test that controllers are also notified. (b/74505936) 229 } 230 } 231 232 @Test 233 public void testBufferingStateChanged() throws Exception { 234 prepareLooper(); 235 final int listSize = 5; 236 final List<MediaItem2> list = TestUtils.createPlaylist(listSize); 237 mMockAgent.setPlaylist(list, null); 238 239 final MediaItem2 currentItem = list.get(3); 240 final int buffState = MediaPlayerBase.BUFFERING_STATE_BUFFERING_COMPLETE; 241 242 final CountDownLatch latchForSessionCallback = new CountDownLatch(1); 243 try (MediaSession2 session = new MediaSession2.Builder(mContext) 244 .setPlayer(mPlayer) 245 .setPlaylistAgent(mMockAgent) 246 .setId("testBufferingStateChanged") 247 .setSessionCallback(sHandlerExecutor, new SessionCallback() { 248 @Override 249 public void onBufferingStateChanged(MediaSession2 session, 250 MediaPlayerBase player, MediaItem2 itemOut, int stateOut) { 251 assertSame(currentItem, itemOut); 252 assertEquals(buffState, stateOut); 253 latchForSessionCallback.countDown(); 254 } 255 }).build()) { 256 257 mPlayer.notifyBufferingStateChanged(currentItem.getDataSourceDesc(), buffState); 258 assertTrue(latchForSessionCallback.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS)); 259 // TODO(jaewan): Test that controllers are also notified. (b/74505936) 260 } 261 } 262 263 /** 264 * This also tests {@link ControllerCallback#onPlaybackSpeedChanged(MediaController2, float)} 265 * and {@link MediaController2#getPlaybackSpeed()}. 266 */ 267 @Test 268 public void testPlaybackSpeedChanged() throws Exception { 269 prepareLooper(); 270 final float speed = 1.5f; 271 mPlayer.setPlaybackSpeed(speed); 272 273 final CountDownLatch latchForSessionCallback = new CountDownLatch(1); 274 try (MediaSession2 session = new MediaSession2.Builder(mContext) 275 .setPlayer(mPlayer) 276 .setId("testPlaybackSpeedChanged") 277 .setSessionCallback(sHandlerExecutor, new SessionCallback() { 278 @Override 279 public void onPlaybackSpeedChanged(MediaSession2 session, 280 MediaPlayerBase player, float speedOut) { 281 assertEquals(speed, speedOut, 0.0f); 282 latchForSessionCallback.countDown(); 283 } 284 }).build()) { 285 286 final CountDownLatch latchForControllerCallback = new CountDownLatch(1); 287 final MediaController2 controller = 288 createController(mSession.getToken(), true, new ControllerCallback() { 289 @Override 290 public void onPlaybackSpeedChanged(MediaController2 controller, 291 float speedOut) { 292 assertEquals(speed, speedOut, 0.0f); 293 latchForControllerCallback.countDown(); 294 } 295 }); 296 297 mPlayer.notifyPlaybackSpeedChanged(speed); 298 assertTrue(latchForSessionCallback.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS)); 299 assertTrue(latchForControllerCallback.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS)); 300 assertEquals(speed, controller.getPlaybackSpeed(), 0.0f); 301 } 302 } 303 304 @Test 305 public void testUpdatePlayer() throws Exception { 306 prepareLooper(); 307 final int targetState = MediaPlayerBase.PLAYER_STATE_PLAYING; 308 final CountDownLatch latch = new CountDownLatch(1); 309 sHandler.postAndSync(new Runnable() { 310 @Override 311 public void run() { 312 mSession.close(); 313 mSession = new MediaSession2.Builder(mContext).setPlayer(mPlayer) 314 .setSessionCallback(sHandlerExecutor, new SessionCallback() { 315 @Override 316 public void onPlayerStateChanged(MediaSession2 session, 317 MediaPlayerBase player, int state) { 318 assertEquals(targetState, state); 319 latch.countDown(); 320 } 321 }).build(); 322 } 323 }); 324 325 MockPlayer player = new MockPlayer(0); 326 327 // Test if setPlayer doesn't crash with various situations. 328 mSession.updatePlayer(mPlayer, null, null); 329 assertEquals(mPlayer, mSession.getPlayer()); 330 MediaPlaylistAgent agent = mSession.getPlaylistAgent(); 331 assertNotNull(agent); 332 333 mSession.updatePlayer(player, null, null); 334 assertEquals(player, mSession.getPlayer()); 335 assertNotNull(mSession.getPlaylistAgent()); 336 assertNotEquals(agent, mSession.getPlaylistAgent()); 337 338 player.notifyPlaybackState(MediaPlayerBase.PLAYER_STATE_PLAYING); 339 assertTrue(latch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS)); 340 } 341 342 @Test 343 public void testSetPlayer_playbackInfo() throws Exception { 344 prepareLooper(); 345 MockPlayer player = new MockPlayer(0); 346 final AudioAttributesCompat attrs = new AudioAttributesCompat.Builder() 347 .setContentType(CONTENT_TYPE_MUSIC) 348 .build(); 349 player.setAudioAttributes(attrs); 350 351 final int maxVolume = 100; 352 final int currentVolume = 23; 353 final int volumeControlType = VOLUME_CONTROL_ABSOLUTE; 354 VolumeProviderCompat volumeProvider = new VolumeProviderCompat( 355 volumeControlType, maxVolume, currentVolume) { }; 356 357 final CountDownLatch latch = new CountDownLatch(1); 358 final ControllerCallback callback = new ControllerCallback() { 359 @Override 360 public void onPlaybackInfoChanged(MediaController2 controller, PlaybackInfo info) { 361 Assert.assertEquals(PlaybackInfo.PLAYBACK_TYPE_REMOTE, info.getPlaybackType()); 362 assertEquals(attrs, info.getAudioAttributes()); 363 assertEquals(volumeControlType, info.getPlaybackType()); 364 assertEquals(maxVolume, info.getMaxVolume()); 365 assertEquals(currentVolume, info.getCurrentVolume()); 366 latch.countDown(); 367 } 368 }; 369 370 mSession.updatePlayer(player, null, null); 371 372 final MediaController2 controller = createController(mSession.getToken(), true, callback); 373 PlaybackInfo info = controller.getPlaybackInfo(); 374 assertNotNull(info); 375 assertEquals(PlaybackInfo.PLAYBACK_TYPE_LOCAL, info.getPlaybackType()); 376 assertEquals(attrs, info.getAudioAttributes()); 377 AudioManager manager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE); 378 379 int localVolumeControlType = VOLUME_CONTROL_ABSOLUTE; 380 if (Build.VERSION.SDK_INT >= 21 && manager.isVolumeFixed()) { 381 localVolumeControlType = VOLUME_CONTROL_FIXED; 382 } 383 assertEquals(localVolumeControlType, info.getControlType()); 384 assertEquals(manager.getStreamMaxVolume(AudioManager.STREAM_MUSIC), info.getMaxVolume()); 385 assertEquals(manager.getStreamVolume(AudioManager.STREAM_MUSIC), info.getCurrentVolume()); 386 387 mSession.updatePlayer(player, null, volumeProvider); 388 assertTrue(latch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS)); 389 390 info = controller.getPlaybackInfo(); 391 assertNotNull(info); 392 assertEquals(PlaybackInfo.PLAYBACK_TYPE_REMOTE, info.getPlaybackType()); 393 assertEquals(attrs, info.getAudioAttributes()); 394 assertEquals(volumeControlType, info.getControlType()); 395 assertEquals(maxVolume, info.getMaxVolume()); 396 assertEquals(currentVolume, info.getCurrentVolume()); 397 } 398 399 @Test 400 public void testPlay() throws Exception { 401 prepareLooper(); 402 mSession.play(); 403 assertTrue(mPlayer.mPlayCalled); 404 } 405 406 @Test 407 public void testPause() throws Exception { 408 prepareLooper(); 409 mSession.pause(); 410 assertTrue(mPlayer.mPauseCalled); 411 } 412 413 @Test 414 public void testReset() throws Exception { 415 prepareLooper(); 416 mSession.reset(); 417 assertTrue(mPlayer.mResetCalled); 418 } 419 420 @Test 421 public void testPrepare() throws Exception { 422 prepareLooper(); 423 mSession.prepare(); 424 assertTrue(mPlayer.mPrepareCalled); 425 } 426 427 @Test 428 public void testSeekTo() throws Exception { 429 prepareLooper(); 430 final long pos = 1004L; 431 mSession.seekTo(pos); 432 assertTrue(mPlayer.mSeekToCalled); 433 assertEquals(pos, mPlayer.mSeekPosition); 434 } 435 436 @Test 437 public void testSetPlaybackSpeed() throws Exception { 438 prepareLooper(); 439 final float speed = 1.5f; 440 mSession.setPlaybackSpeed(speed); 441 assertTrue(mPlayer.mSetPlaybackSpeedCalled); 442 assertEquals(speed, mPlayer.mPlaybackSpeed, 0.0f); 443 } 444 445 @Test 446 public void testGetPlaybackSpeed() throws Exception { 447 prepareLooper(); 448 final float speed = 1.5f; 449 mPlayer.setPlaybackSpeed(speed); 450 assertEquals(speed, mSession.getPlaybackSpeed(), 0.0f); 451 } 452 453 @Test 454 public void testGetCurrentMediaItem() { 455 prepareLooper(); 456 MediaItem2 item = TestUtils.createMediaItemWithMetadata(); 457 mMockAgent.mCurrentMediaItem = item; 458 assertEquals(item, mSession.getCurrentMediaItem()); 459 } 460 461 @Test 462 public void testSkipToPreviousItem() { 463 prepareLooper(); 464 mSession.skipToPreviousItem(); 465 assertTrue(mMockAgent.mSkipToPreviousItemCalled); 466 } 467 468 @Test 469 public void testSkipToNextItem() throws Exception { 470 prepareLooper(); 471 mSession.skipToNextItem(); 472 assertTrue(mMockAgent.mSkipToNextItemCalled); 473 } 474 475 @Test 476 public void testSkipToPlaylistItem() throws Exception { 477 prepareLooper(); 478 final MediaItem2 testMediaItem = TestUtils.createMediaItemWithMetadata(); 479 mSession.skipToPlaylistItem(testMediaItem); 480 assertTrue(mMockAgent.mSkipToPlaylistItemCalled); 481 assertSame(testMediaItem, mMockAgent.mItem); 482 } 483 484 @Test 485 public void testGetPlayerState() { 486 prepareLooper(); 487 final int state = MediaPlayerBase.PLAYER_STATE_PLAYING; 488 mPlayer.mLastPlayerState = state; 489 assertEquals(state, mSession.getPlayerState()); 490 } 491 492 @Test 493 public void testGetPosition() { 494 prepareLooper(); 495 final long position = 150000; 496 mPlayer.mCurrentPosition = position; 497 assertEquals(position, mSession.getCurrentPosition()); 498 } 499 500 @Test 501 public void testGetBufferedPosition() { 502 prepareLooper(); 503 final long bufferedPosition = 900000; 504 mPlayer.mBufferedPosition = bufferedPosition; 505 assertEquals(bufferedPosition, mSession.getBufferedPosition()); 506 } 507 508 @Test 509 public void testSetPlaylist() { 510 prepareLooper(); 511 final List<MediaItem2> list = TestUtils.createPlaylist(2); 512 mSession.setPlaylist(list, null); 513 assertTrue(mMockAgent.mSetPlaylistCalled); 514 assertSame(list, mMockAgent.mPlaylist); 515 assertNull(mMockAgent.mMetadata); 516 } 517 518 @Test 519 public void testGetPlaylist() { 520 prepareLooper(); 521 final List<MediaItem2> list = TestUtils.createPlaylist(2); 522 mMockAgent.mPlaylist = list; 523 assertEquals(list, mSession.getPlaylist()); 524 } 525 526 @Test 527 public void testUpdatePlaylistMetadata() { 528 prepareLooper(); 529 final MediaMetadata2 testMetadata = TestUtils.createMetadata(); 530 mSession.updatePlaylistMetadata(testMetadata); 531 assertTrue(mMockAgent.mUpdatePlaylistMetadataCalled); 532 assertSame(testMetadata, mMockAgent.mMetadata); 533 } 534 535 @Test 536 public void testGetPlaylistMetadata() { 537 prepareLooper(); 538 final MediaMetadata2 testMetadata = TestUtils.createMetadata(); 539 mMockAgent.mMetadata = testMetadata; 540 assertEquals(testMetadata, mSession.getPlaylistMetadata()); 541 } 542 543 @Test 544 public void testSessionCallback_onPlaylistChanged() throws InterruptedException { 545 prepareLooper(); 546 final List<MediaItem2> list = TestUtils.createPlaylist(2); 547 final CountDownLatch latch = new CountDownLatch(1); 548 mMockAgent.setPlaylist(list, null); 549 550 final SessionCallback sessionCallback = new SessionCallback() { 551 @Override 552 public void onPlaylistChanged(MediaSession2 session, MediaPlaylistAgent playlistAgent, 553 List<MediaItem2> playlist, MediaMetadata2 metadata) { 554 assertEquals(mMockAgent, playlistAgent); 555 assertEquals(list, playlist); 556 assertNull(metadata); 557 latch.countDown(); 558 } 559 }; 560 try (MediaSession2 session = new MediaSession2.Builder(mContext) 561 .setPlayer(mPlayer) 562 .setPlaylistAgent(mMockAgent) 563 .setId("testSessionCallback") 564 .setSessionCallback(sHandlerExecutor, sessionCallback) 565 .build()) { 566 mMockAgent.notifyPlaylistChanged(); 567 assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); 568 } 569 } 570 571 @Test 572 public void testAddPlaylistItem() { 573 prepareLooper(); 574 final int testIndex = 12; 575 final MediaItem2 testMediaItem = TestUtils.createMediaItemWithMetadata(); 576 mSession.addPlaylistItem(testIndex, testMediaItem); 577 assertTrue(mMockAgent.mAddPlaylistItemCalled); 578 assertEquals(testIndex, mMockAgent.mIndex); 579 assertSame(testMediaItem, mMockAgent.mItem); 580 } 581 582 @Test 583 public void testRemovePlaylistItem() { 584 prepareLooper(); 585 final MediaItem2 testMediaItem = TestUtils.createMediaItemWithMetadata(); 586 mSession.removePlaylistItem(testMediaItem); 587 assertTrue(mMockAgent.mRemovePlaylistItemCalled); 588 assertSame(testMediaItem, mMockAgent.mItem); 589 } 590 591 @Test 592 public void testReplacePlaylistItem() throws InterruptedException { 593 prepareLooper(); 594 final int testIndex = 12; 595 final MediaItem2 testMediaItem = TestUtils.createMediaItemWithMetadata(); 596 mSession.replacePlaylistItem(testIndex, testMediaItem); 597 assertTrue(mMockAgent.mReplacePlaylistItemCalled); 598 assertEquals(testIndex, mMockAgent.mIndex); 599 assertSame(testMediaItem, mMockAgent.mItem); 600 } 601 602 /** 603 * This also tests {@link SessionCallback#onShuffleModeChanged} 604 */ 605 @Test 606 public void testGetShuffleMode() throws InterruptedException { 607 prepareLooper(); 608 final int testShuffleMode = MediaPlaylistAgent.SHUFFLE_MODE_GROUP; 609 mMockAgent.setShuffleMode(testShuffleMode); 610 611 final CountDownLatch latch = new CountDownLatch(1); 612 final SessionCallback sessionCallback = new SessionCallback() { 613 @Override 614 public void onShuffleModeChanged(MediaSession2 session, 615 MediaPlaylistAgent playlistAgent, int shuffleMode) { 616 assertEquals(mMockAgent, playlistAgent); 617 assertEquals(testShuffleMode, shuffleMode); 618 latch.countDown(); 619 } 620 }; 621 try (MediaSession2 session = new MediaSession2.Builder(mContext) 622 .setPlayer(mPlayer) 623 .setPlaylistAgent(mMockAgent) 624 .setId("testGetShuffleMode") 625 .setSessionCallback(sHandlerExecutor, sessionCallback) 626 .build()) { 627 mMockAgent.notifyShuffleModeChanged(); 628 assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); 629 } 630 } 631 632 @Test 633 public void testSetShuffleMode() { 634 prepareLooper(); 635 final int testShuffleMode = MediaPlaylistAgent.SHUFFLE_MODE_GROUP; 636 mSession.setShuffleMode(testShuffleMode); 637 assertTrue(mMockAgent.mSetShuffleModeCalled); 638 assertEquals(testShuffleMode, mMockAgent.mShuffleMode); 639 } 640 641 /** 642 * This also tests {@link SessionCallback#onShuffleModeChanged} 643 */ 644 @Test 645 public void testGetRepeatMode() throws InterruptedException { 646 prepareLooper(); 647 final int testRepeatMode = MediaPlaylistAgent.REPEAT_MODE_GROUP; 648 mMockAgent.setRepeatMode(testRepeatMode); 649 650 final CountDownLatch latch = new CountDownLatch(1); 651 final SessionCallback sessionCallback = new SessionCallback() { 652 @Override 653 public void onRepeatModeChanged(MediaSession2 session, MediaPlaylistAgent playlistAgent, 654 int repeatMode) { 655 assertEquals(mMockAgent, playlistAgent); 656 assertEquals(testRepeatMode, repeatMode); 657 latch.countDown(); 658 } 659 }; 660 try (MediaSession2 session = new MediaSession2.Builder(mContext) 661 .setPlayer(mPlayer) 662 .setPlaylistAgent(mMockAgent) 663 .setId("testGetRepeatMode") 664 .setSessionCallback(sHandlerExecutor, sessionCallback) 665 .build()) { 666 mMockAgent.notifyRepeatModeChanged(); 667 assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); 668 } 669 } 670 671 @Test 672 public void testSetRepeatMode() { 673 prepareLooper(); 674 final int testRepeatMode = MediaPlaylistAgent.REPEAT_MODE_GROUP; 675 mSession.setRepeatMode(testRepeatMode); 676 assertTrue(mMockAgent.mSetRepeatModeCalled); 677 assertEquals(testRepeatMode, mMockAgent.mRepeatMode); 678 } 679 680 // TODO(jaewan): Revisit 681 @Ignore 682 @Test 683 public void testBadPlayer() throws InterruptedException { 684 prepareLooper(); 685 // TODO(jaewan): Add equivalent tests again 686 final CountDownLatch latch = new CountDownLatch(4); // expected call + 1 687 final BadPlayer player = new BadPlayer(0); 688 689 mSession.updatePlayer(player, null, null); 690 mSession.updatePlayer(mPlayer, null, null); 691 player.notifyPlaybackState(MediaPlayerBase.PLAYER_STATE_PAUSED); 692 assertFalse(latch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS)); 693 } 694 695 // This bad player will keep push events to the listener that is previously 696 // registered by session.setPlayer(). 697 private static class BadPlayer extends MockPlayer { 698 BadPlayer(int count) { 699 super(count); 700 } 701 702 @Override 703 public void unregisterPlayerEventCallback( 704 @NonNull MediaPlayerBase.PlayerEventCallback listener) { 705 // No-op. 706 } 707 } 708 709 @Test 710 public void testOnCommandCallback() throws InterruptedException { 711 prepareLooper(); 712 final MockOnCommandCallback callback = new MockOnCommandCallback(); 713 sHandler.postAndSync(new Runnable() { 714 @Override 715 public void run() { 716 mSession.close(); 717 mPlayer = new MockPlayer(1); 718 mSession = new MediaSession2.Builder(mContext).setPlayer(mPlayer) 719 .setSessionCallback(sHandlerExecutor, callback).build(); 720 } 721 }); 722 MediaController2 controller = createController(mSession.getToken()); 723 controller.pause(); 724 assertFalse(mPlayer.mCountDownLatch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS)); 725 assertFalse(mPlayer.mPauseCalled); 726 assertEquals(1, callback.commands.size()); 727 assertEquals(SessionCommand2.COMMAND_CODE_PLAYBACK_PAUSE, 728 (long) callback.commands.get(0).getCommandCode()); 729 730 controller.play(); 731 assertTrue(mPlayer.mCountDownLatch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS)); 732 assertTrue(mPlayer.mPlayCalled); 733 assertFalse(mPlayer.mPauseCalled); 734 assertEquals(2, callback.commands.size()); 735 assertEquals(SessionCommand2.COMMAND_CODE_PLAYBACK_PLAY, 736 (long) callback.commands.get(1).getCommandCode()); 737 } 738 739 @Test 740 public void testOnConnectCallback() throws InterruptedException { 741 prepareLooper(); 742 final MockOnConnectCallback sessionCallback = new MockOnConnectCallback(); 743 sHandler.postAndSync(new Runnable() { 744 @Override 745 public void run() { 746 mSession.close(); 747 mSession = new MediaSession2.Builder(mContext).setPlayer(mPlayer) 748 .setSessionCallback(sHandlerExecutor, sessionCallback).build(); 749 } 750 }); 751 MediaController2 controller = createController(mSession.getToken(), false, null); 752 assertNotNull(controller); 753 waitForConnect(controller, false); 754 waitForDisconnect(controller, true); 755 } 756 757 @Test 758 public void testOnDisconnectCallback() throws InterruptedException { 759 prepareLooper(); 760 final CountDownLatch latch = new CountDownLatch(1); 761 try (MediaSession2 session = new MediaSession2.Builder(mContext) 762 .setPlayer(mPlayer) 763 .setId("testOnDisconnectCallback") 764 .setSessionCallback(sHandlerExecutor, new SessionCallback() { 765 @Override 766 public void onDisconnected(MediaSession2 session, 767 ControllerInfo controller) { 768 assertEquals(Process.myUid(), controller.getUid()); 769 latch.countDown(); 770 } 771 }).build()) { 772 MediaController2 controller = createController(session.getToken()); 773 controller.close(); 774 assertTrue(latch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS)); 775 } 776 } 777 778 @Test 779 public void testSetCustomLayout() throws InterruptedException { 780 prepareLooper(); 781 final List<CommandButton> buttons = new ArrayList<>(); 782 buttons.add(new CommandButton.Builder() 783 .setCommand(new SessionCommand2(SessionCommand2.COMMAND_CODE_PLAYBACK_PLAY)) 784 .setDisplayName("button").build()); 785 final CountDownLatch latch = new CountDownLatch(1); 786 final SessionCallback sessionCallback = new SessionCallback() { 787 @Override 788 public SessionCommandGroup2 onConnect(MediaSession2 session, 789 ControllerInfo controller) { 790 if (mContext.getPackageName().equals(controller.getPackageName())) { 791 mSession.setCustomLayout(controller, buttons); 792 } 793 return super.onConnect(session, controller); 794 } 795 }; 796 797 try (MediaSession2 session = new MediaSession2.Builder(mContext) 798 .setPlayer(mPlayer) 799 .setId("testSetCustomLayout") 800 .setSessionCallback(sHandlerExecutor, sessionCallback) 801 .build()) { 802 if (mSession != null) { 803 mSession.close(); 804 mSession = session; 805 } 806 final ControllerCallback callback = new ControllerCallback() { 807 @Override 808 public void onCustomLayoutChanged(MediaController2 controller2, 809 List<CommandButton> layout) { 810 assertEquals(layout.size(), buttons.size()); 811 for (int i = 0; i < layout.size(); i++) { 812 assertEquals(layout.get(i).getCommand(), buttons.get(i).getCommand()); 813 assertEquals(layout.get(i).getDisplayName(), 814 buttons.get(i).getDisplayName()); 815 } 816 latch.countDown(); 817 } 818 }; 819 final MediaController2 controller = 820 createController(session.getToken(), true, callback); 821 assertTrue(latch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS)); 822 } 823 } 824 825 @Test 826 public void testSetAllowedCommands() throws InterruptedException { 827 prepareLooper(); 828 final SessionCommandGroup2 commands = new SessionCommandGroup2(); 829 commands.addCommand(new SessionCommand2(SessionCommand2.COMMAND_CODE_PLAYBACK_PLAY)); 830 commands.addCommand(new SessionCommand2(SessionCommand2.COMMAND_CODE_PLAYBACK_PAUSE)); 831 commands.addCommand(new SessionCommand2(SessionCommand2.COMMAND_CODE_PLAYBACK_RESET)); 832 833 final CountDownLatch latch = new CountDownLatch(1); 834 final ControllerCallback callback = new ControllerCallback() { 835 @Override 836 public void onAllowedCommandsChanged(MediaController2 controller, 837 SessionCommandGroup2 commandsOut) { 838 assertNotNull(commandsOut); 839 Set<SessionCommand2> expected = commands.getCommands(); 840 Set<SessionCommand2> actual = commandsOut.getCommands(); 841 842 assertNotNull(actual); 843 assertEquals(expected.size(), actual.size()); 844 for (SessionCommand2 command : expected) { 845 assertTrue(actual.contains(command)); 846 } 847 latch.countDown(); 848 } 849 }; 850 851 final MediaController2 controller = createController(mSession.getToken(), true, callback); 852 ControllerInfo controllerInfo = getTestControllerInfo(); 853 assertNotNull(controllerInfo); 854 855 mSession.setAllowedCommands(controllerInfo, commands); 856 assertTrue(latch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS)); 857 } 858 859 @Test 860 public void testSendCustomCommand() throws InterruptedException { 861 prepareLooper(); 862 final SessionCommand2 testCommand = new SessionCommand2( 863 SessionCommand2.COMMAND_CODE_PLAYBACK_PREPARE); 864 final Bundle testArgs = new Bundle(); 865 testArgs.putString("args", "testSendCustomAction"); 866 867 final CountDownLatch latch = new CountDownLatch(2); 868 final ControllerCallback callback = new ControllerCallback() { 869 @Override 870 public void onCustomCommand(MediaController2 controller, SessionCommand2 command, 871 Bundle args, ResultReceiver receiver) { 872 assertEquals(testCommand, command); 873 assertTrue(TestUtils.equals(testArgs, args)); 874 assertNull(receiver); 875 latch.countDown(); 876 } 877 }; 878 final MediaController2 controller = 879 createController(mSession.getToken(), true, callback); 880 // TODO(jaewan): Test with multiple controllers 881 mSession.sendCustomCommand(testCommand, testArgs); 882 883 ControllerInfo controllerInfo = getTestControllerInfo(); 884 assertNotNull(controllerInfo); 885 // TODO(jaewan): Test receivers as well. 886 mSession.sendCustomCommand(controllerInfo, testCommand, testArgs, null); 887 assertTrue(latch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS)); 888 } 889 890 @Test 891 public void testNotifyError() throws InterruptedException { 892 prepareLooper(); 893 final int errorCode = MediaSession2.ERROR_CODE_NOT_AVAILABLE_IN_REGION; 894 final Bundle extras = new Bundle(); 895 extras.putString("args", "testNotifyError"); 896 897 final CountDownLatch latch = new CountDownLatch(1); 898 final ControllerCallback callback = new ControllerCallback() { 899 @Override 900 public void onError(MediaController2 controller, int errorCodeOut, Bundle extrasOut) { 901 assertEquals(errorCode, errorCodeOut); 902 assertTrue(TestUtils.equals(extras, extrasOut)); 903 latch.countDown(); 904 } 905 }; 906 final MediaController2 controller = createController(mSession.getToken(), true, callback); 907 // TODO(jaewan): Test with multiple controllers 908 mSession.notifyError(errorCode, extras); 909 assertTrue(latch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS)); 910 } 911 912 @Test 913 public void testNotifyRoutesInfoChanged() throws InterruptedException { 914 prepareLooper(); 915 final CountDownLatch latch = new CountDownLatch(1); 916 final ControllerCallback callback = new ControllerCallback() { 917 @Override 918 public void onRoutesInfoChanged(@NonNull MediaController2 controller, 919 @Nullable List<Bundle> routes) { 920 assertNull(routes); 921 latch.countDown(); 922 } 923 }; 924 final MediaController2 controller = createController(mSession.getToken(), true, callback); 925 ControllerInfo controllerInfo = getTestControllerInfo(); 926 mSession.notifyRoutesInfoChanged(controllerInfo, null); 927 assertTrue(latch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS)); 928 } 929 930 private ControllerInfo getTestControllerInfo() { 931 List<ControllerInfo> controllers = mSession.getConnectedControllers(); 932 assertNotNull(controllers); 933 for (int i = 0; i < controllers.size(); i++) { 934 if (Process.myUid() == controllers.get(i).getUid()) { 935 return controllers.get(i); 936 } 937 } 938 fail("Failed to get test controller info"); 939 return null; 940 } 941 942 public class MockOnConnectCallback extends SessionCallback { 943 @Override 944 public SessionCommandGroup2 onConnect(MediaSession2 session, 945 ControllerInfo controllerInfo) { 946 if (Process.myUid() != controllerInfo.getUid()) { 947 return null; 948 } 949 assertEquals(mContext.getPackageName(), controllerInfo.getPackageName()); 950 assertEquals(Process.myUid(), controllerInfo.getUid()); 951 assertFalse(controllerInfo.isTrusted()); 952 // Reject all 953 return null; 954 } 955 } 956 957 public class MockOnCommandCallback extends SessionCallback { 958 public final ArrayList<SessionCommand2> commands = new ArrayList<>(); 959 960 @Override 961 public boolean onCommandRequest(MediaSession2 session, ControllerInfo controllerInfo, 962 SessionCommand2 command) { 963 assertEquals(mContext.getPackageName(), controllerInfo.getPackageName()); 964 assertEquals(Process.myUid(), controllerInfo.getUid()); 965 assertFalse(controllerInfo.isTrusted()); 966 commands.add(command); 967 if (command.getCommandCode() == SessionCommand2.COMMAND_CODE_PLAYBACK_PAUSE) { 968 return false; 969 } 970 return true; 971 } 972 } 973 974 private static void assertMediaItemListEquals(List<MediaItem2> a, List<MediaItem2> b) { 975 if (a == null || b == null) { 976 assertEquals(a, b); 977 } 978 assertEquals(a.size(), b.size()); 979 980 for (int i = 0; i < a.size(); i++) { 981 MediaItem2 aItem = a.get(i); 982 MediaItem2 bItem = b.get(i); 983 984 if (aItem == null || bItem == null) { 985 assertEquals(aItem, bItem); 986 continue; 987 } 988 989 assertEquals(aItem.getMediaId(), bItem.getMediaId()); 990 assertEquals(aItem.getFlags(), bItem.getFlags()); 991 TestUtils.equals(aItem.getMetadata().toBundle(), bItem.getMetadata().toBundle()); 992 993 // Note: Here it does not check whether DataSourceDesc are equal, 994 // since there DataSourceDec is not comparable. 995 } 996 } 997} 998