MediaController2Test.java revision 8138c8606070fc6193f0a9bc566c4b5f1d035457
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 org.junit.Assert.assertEquals; 20import static org.junit.Assert.assertFalse; 21import static org.junit.Assert.assertNotEquals; 22import static org.junit.Assert.assertNotNull; 23import static org.junit.Assert.assertNull; 24import static org.junit.Assert.assertTrue; 25import static org.junit.Assert.fail; 26 27import android.app.PendingIntent; 28import android.content.Intent; 29import android.media.AudioManager; 30import android.net.Uri; 31import android.os.Build; 32import android.os.Bundle; 33import android.os.Handler; 34import android.os.HandlerThread; 35import android.os.Process; 36import android.os.ResultReceiver; 37import android.support.test.filters.FlakyTest; 38import android.support.test.filters.SdkSuppress; 39import android.support.test.filters.SmallTest; 40import android.support.test.runner.AndroidJUnit4; 41 42import androidx.annotation.NonNull; 43import androidx.media.MediaController2.ControllerCallback; 44import androidx.media.MediaLibraryService2.MediaLibrarySession.MediaLibrarySessionCallback; 45import androidx.media.MediaSession2.ControllerInfo; 46import androidx.media.MediaSession2.SessionCallback; 47import androidx.media.TestServiceRegistry.SessionServiceCallback; 48import androidx.media.TestUtils.SyncHandler; 49 50import org.junit.After; 51import org.junit.Before; 52import org.junit.Ignore; 53import org.junit.Test; 54import org.junit.runner.RunWith; 55 56import java.lang.reflect.Method; 57import java.util.List; 58import java.util.concurrent.CountDownLatch; 59import java.util.concurrent.TimeUnit; 60import java.util.concurrent.atomic.AtomicReference; 61 62/** 63 * Tests {@link MediaController2}. 64 */ 65// TODO(jaewan): Implement host-side test so controller and session can run in different processes. 66// TODO(jaewan): Fix flaky failure -- see MediaController2Impl.getController() 67// TODO(jaeawn): Revisit create/close session in the sHandler. It's no longer necessary. 68@SdkSuppress(minSdkVersion = Build.VERSION_CODES.KITKAT) 69@RunWith(AndroidJUnit4.class) 70@SmallTest 71@FlakyTest 72public class MediaController2Test extends MediaSession2TestBase { 73 private static final String TAG = "MediaController2Test"; 74 75 PendingIntent mIntent; 76 MediaSession2 mSession; 77 MediaController2 mController; 78 MockPlayer mPlayer; 79 MockPlaylistAgent mMockAgent; 80 81 @Before 82 @Override 83 public void setUp() throws Exception { 84 super.setUp(); 85 final Intent sessionActivity = new Intent(mContext, MockActivity.class); 86 // Create this test specific MediaSession2 to use our own Handler. 87 mIntent = PendingIntent.getActivity(mContext, 0, sessionActivity, 0); 88 89 mPlayer = new MockPlayer(1); 90 mMockAgent = new MockPlaylistAgent(); 91 mSession = new MediaSession2.Builder(mContext) 92 .setPlayer(mPlayer) 93 .setPlaylistAgent(mMockAgent) 94 .setSessionCallback(sHandlerExecutor, new SessionCallback() { 95 @Override 96 public SessionCommandGroup2 onConnect(MediaSession2 session, 97 ControllerInfo controller) { 98 if (Process.myUid() == controller.getUid()) { 99 return super.onConnect(session, controller); 100 } 101 return null; 102 } 103 104 @Override 105 public void onPlaylistMetadataChanged(MediaSession2 session, 106 MediaPlaylistAgent playlistAgent, 107 MediaMetadata2 metadata) { 108 super.onPlaylistMetadataChanged(session, playlistAgent, metadata); 109 } 110 }) 111 .setSessionActivity(mIntent) 112 .setId(TAG).build(); 113 mController = createController(mSession.getToken()); 114 TestServiceRegistry.getInstance().setHandler(sHandler); 115 } 116 117 @After 118 @Override 119 public void cleanUp() throws Exception { 120 super.cleanUp(); 121 if (mSession != null) { 122 mSession.close(); 123 } 124 TestServiceRegistry.getInstance().cleanUp(); 125 } 126 127 /** 128 * Test if the {@link MediaSession2TestBase.TestControllerCallback} wraps the callback proxy 129 * without missing any method. 130 */ 131 @Test 132 public void testTestControllerCallback() { 133 prepareLooper(); 134 Method[] methods = TestControllerCallback.class.getMethods(); 135 assertNotNull(methods); 136 for (int i = 0; i < methods.length; i++) { 137 // For any methods in the controller callback, TestControllerCallback should have 138 // overriden the method and call matching API in the callback proxy. 139 assertNotEquals("TestControllerCallback should override " + methods[i] 140 + " and call callback proxy", 141 ControllerCallback.class, methods[i].getDeclaringClass()); 142 } 143 } 144 145 @Test 146 public void testPlay() { 147 prepareLooper(); 148 mController.play(); 149 try { 150 assertTrue(mPlayer.mCountDownLatch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS)); 151 } catch (InterruptedException e) { 152 fail(e.getMessage()); 153 } 154 assertTrue(mPlayer.mPlayCalled); 155 } 156 157 @Test 158 public void testPause() { 159 prepareLooper(); 160 mController.pause(); 161 try { 162 assertTrue(mPlayer.mCountDownLatch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS)); 163 } catch (InterruptedException e) { 164 fail(e.getMessage()); 165 } 166 assertTrue(mPlayer.mPauseCalled); 167 } 168 169 @Test 170 public void testReset() { 171 prepareLooper(); 172 mController.reset(); 173 try { 174 assertTrue(mPlayer.mCountDownLatch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS)); 175 } catch (InterruptedException e) { 176 fail(e.getMessage()); 177 } 178 assertTrue(mPlayer.mResetCalled); 179 } 180 181 @Test 182 public void testPrepare() { 183 prepareLooper(); 184 mController.prepare(); 185 try { 186 assertTrue(mPlayer.mCountDownLatch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS)); 187 } catch (InterruptedException e) { 188 fail(e.getMessage()); 189 } 190 assertTrue(mPlayer.mPrepareCalled); 191 } 192 193 @Test 194 public void testSeekTo() { 195 prepareLooper(); 196 final long seekPosition = 12125L; 197 mController.seekTo(seekPosition); 198 try { 199 assertTrue(mPlayer.mCountDownLatch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS)); 200 } catch (InterruptedException e) { 201 fail(e.getMessage()); 202 } 203 assertTrue(mPlayer.mSeekToCalled); 204 assertEquals(seekPosition, mPlayer.mSeekPosition); 205 } 206 207 @Test 208 public void testGettersAfterConnected() throws InterruptedException { 209 prepareLooper(); 210 final int state = MediaPlayerBase.PLAYER_STATE_PLAYING; 211 final int bufferingState = MediaPlayerBase.BUFFERING_STATE_BUFFERING_COMPLETE; 212 final long position = 150000; 213 final long bufferedPosition = 900000; 214 final float speed = 0.5f; 215 final MediaItem2 currentMediaItem = TestUtils.createMediaItemWithMetadata(); 216 217 mPlayer.mLastPlayerState = state; 218 mPlayer.mLastBufferingState = bufferingState; 219 mPlayer.mCurrentPosition = position; 220 mPlayer.mBufferedPosition = bufferedPosition; 221 mPlayer.mPlaybackSpeed = speed; 222 mMockAgent.mCurrentMediaItem = currentMediaItem; 223 224 long time1 = System.currentTimeMillis(); 225 MediaController2 controller = createController(mSession.getToken()); 226 long time2 = System.currentTimeMillis(); 227 assertEquals(state, controller.getPlayerState()); 228 assertEquals(bufferedPosition, controller.getBufferedPosition()); 229 assertEquals(speed, controller.getPlaybackSpeed(), 0.0f); 230 long positionLowerBound = (long) (position + speed * (System.currentTimeMillis() - time2)); 231 long currentPosition = controller.getCurrentPosition(); 232 long positionUpperBound = (long) (position + speed * (System.currentTimeMillis() - time1)); 233 assertTrue("curPos=" + currentPosition + ", lowerBound=" + positionLowerBound 234 + ", upperBound=" + positionUpperBound, 235 positionLowerBound <= currentPosition && currentPosition <= positionUpperBound); 236 assertEquals(currentMediaItem, controller.getCurrentMediaItem()); 237 } 238 239 @Test 240 public void testGetSessionActivity() { 241 prepareLooper(); 242 PendingIntent sessionActivity = mController.getSessionActivity(); 243 assertEquals(mContext.getPackageName(), sessionActivity.getCreatorPackage()); 244 assertEquals(Process.myUid(), sessionActivity.getCreatorUid()); 245 } 246 247 @Test 248 public void testSetPlaylist() throws InterruptedException { 249 prepareLooper(); 250 final List<MediaItem2> list = TestUtils.createPlaylist(2); 251 mController.setPlaylist(list, null /* Metadata */); 252 assertTrue(mMockAgent.mCountDownLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); 253 254 assertTrue(mMockAgent.mSetPlaylistCalled); 255 assertNull(mMockAgent.mMetadata); 256 257 assertNotNull(mMockAgent.mPlaylist); 258 assertEquals(list.size(), mMockAgent.mPlaylist.size()); 259 for (int i = 0; i < list.size(); i++) { 260 // MediaController2.setPlaylist does not ensure the equality of the items. 261 assertEquals(list.get(i).getMediaId(), mMockAgent.mPlaylist.get(i).getMediaId()); 262 } 263 } 264 265 /** 266 * This also tests {@link ControllerCallback#onPlaylistChanged( 267 * MediaController2, List, MediaMetadata2)}. 268 */ 269 @Test 270 public void testGetPlaylist() throws InterruptedException { 271 prepareLooper(); 272 final List<MediaItem2> testList = TestUtils.createPlaylist(2); 273 final AtomicReference<List<MediaItem2>> listFromCallback = new AtomicReference<>(); 274 final CountDownLatch latch = new CountDownLatch(1); 275 final ControllerCallback callback = new ControllerCallback() { 276 @Override 277 public void onPlaylistChanged(MediaController2 controller, 278 List<MediaItem2> playlist, MediaMetadata2 metadata) { 279 assertNotNull(playlist); 280 assertEquals(testList.size(), playlist.size()); 281 for (int i = 0; i < playlist.size(); i++) { 282 assertEquals(testList.get(i).getMediaId(), playlist.get(i).getMediaId()); 283 } 284 listFromCallback.set(playlist); 285 latch.countDown(); 286 } 287 }; 288 final MediaPlaylistAgent agent = new MockPlaylistAgent() { 289 @Override 290 public List<MediaItem2> getPlaylist() { 291 return testList; 292 } 293 }; 294 try (MediaSession2 session = new MediaSession2.Builder(mContext) 295 .setPlayer(mPlayer) 296 .setId("testControllerCallback_onPlaylistChanged") 297 .setSessionCallback(sHandlerExecutor, new SessionCallback() {}) 298 .setPlaylistAgent(agent) 299 .build()) { 300 MediaController2 controller = createController( 301 session.getToken(), true, callback); 302 agent.notifyPlaylistChanged(); 303 assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); 304 assertEquals(listFromCallback.get(), controller.getPlaylist()); 305 } 306 } 307 308 @Test 309 public void testUpdatePlaylistMetadata() throws InterruptedException { 310 prepareLooper(); 311 final MediaMetadata2 testMetadata = TestUtils.createMetadata(); 312 mController.updatePlaylistMetadata(testMetadata); 313 assertTrue(mMockAgent.mCountDownLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); 314 315 assertTrue(mMockAgent.mUpdatePlaylistMetadataCalled); 316 assertNotNull(mMockAgent.mMetadata); 317 assertEquals(testMetadata.getMediaId(), mMockAgent.mMetadata.getMediaId()); 318 } 319 320 @Test 321 public void testGetPlaylistMetadata() throws InterruptedException { 322 prepareLooper(); 323 final MediaMetadata2 testMetadata = TestUtils.createMetadata(); 324 final AtomicReference<MediaMetadata2> metadataFromCallback = new AtomicReference<>(); 325 final CountDownLatch latch = new CountDownLatch(1); 326 final ControllerCallback callback = new ControllerCallback() { 327 @Override 328 public void onPlaylistMetadataChanged(MediaController2 controller, 329 MediaMetadata2 metadata) { 330 assertNotNull(testMetadata); 331 assertEquals(testMetadata.getMediaId(), metadata.getMediaId()); 332 metadataFromCallback.set(metadata); 333 latch.countDown(); 334 } 335 }; 336 final MediaPlaylistAgent agent = new MockPlaylistAgent() { 337 @Override 338 public MediaMetadata2 getPlaylistMetadata() { 339 return testMetadata; 340 } 341 }; 342 try (MediaSession2 session = new MediaSession2.Builder(mContext) 343 .setPlayer(mPlayer) 344 .setId("testGetPlaylistMetadata") 345 .setSessionCallback(sHandlerExecutor, new SessionCallback() {}) 346 .setPlaylistAgent(agent) 347 .build()) { 348 MediaController2 controller = createController(session.getToken(), true, callback); 349 agent.notifyPlaylistMetadataChanged(); 350 assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); 351 assertEquals(metadataFromCallback.get().getMediaId(), 352 controller.getPlaylistMetadata().getMediaId()); 353 } 354 } 355 356 @Test 357 public void testSetPlaybackSpeed() throws Exception { 358 prepareLooper(); 359 final float speed = 1.5f; 360 mController.setPlaybackSpeed(speed); 361 assertTrue(mPlayer.mCountDownLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); 362 assertEquals(speed, mPlayer.mPlaybackSpeed, 0.0f); 363 } 364 365 /** 366 * Test whether {@link MediaSession2#setPlaylist(List, MediaMetadata2)} is notified 367 * through the 368 * {@link ControllerCallback#onPlaylistMetadataChanged(MediaController2, MediaMetadata2)} 369 * if the controller doesn't have {@link SessionCommand2#COMMAND_CODE_PLAYLIST_GET_LIST} but 370 * {@link SessionCommand2#COMMAND_CODE_PLAYLIST_GET_LIST_METADATA}. 371 */ 372 @Test 373 public void testControllerCallback_onPlaylistMetadataChanged() throws InterruptedException { 374 prepareLooper(); 375 final MediaItem2 item = TestUtils.createMediaItemWithMetadata(); 376 final List<MediaItem2> list = TestUtils.createPlaylist(2); 377 final CountDownLatch latch = new CountDownLatch(1); 378 final ControllerCallback callback = new ControllerCallback() { 379 @Override 380 public void onPlaylistMetadataChanged(MediaController2 controller, 381 MediaMetadata2 metadata) { 382 assertNotNull(metadata); 383 assertEquals(item.getMediaId(), metadata.getMediaId()); 384 latch.countDown(); 385 } 386 }; 387 final SessionCallback sessionCallback = new SessionCallback() { 388 @Override 389 public SessionCommandGroup2 onConnect(MediaSession2 session, 390 ControllerInfo controller) { 391 if (Process.myUid() == controller.getUid()) { 392 SessionCommandGroup2 commands = new SessionCommandGroup2(); 393 commands.addCommand(new SessionCommand2( 394 SessionCommand2.COMMAND_CODE_PLAYLIST_GET_LIST_METADATA)); 395 return commands; 396 } 397 return super.onConnect(session, controller); 398 } 399 }; 400 final MediaPlaylistAgent agent = new MockPlaylistAgent() { 401 @Override 402 public MediaMetadata2 getPlaylistMetadata() { 403 return item.getMetadata(); 404 } 405 406 @Override 407 public List<MediaItem2> getPlaylist() { 408 return list; 409 } 410 }; 411 try (MediaSession2 session = new MediaSession2.Builder(mContext) 412 .setPlayer(mPlayer) 413 .setId("testControllerCallback_onPlaylistMetadataChanged") 414 .setSessionCallback(sHandlerExecutor, sessionCallback) 415 .setPlaylistAgent(agent) 416 .build()) { 417 MediaController2 controller = createController(session.getToken(), true, callback); 418 agent.notifyPlaylistMetadataChanged(); 419 assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); 420 } 421 } 422 423 @Test 424 public void testAddPlaylistItem() throws InterruptedException { 425 prepareLooper(); 426 final int testIndex = 12; 427 final MediaItem2 testMediaItem = TestUtils.createMediaItemWithMetadata(); 428 mController.addPlaylistItem(testIndex, testMediaItem); 429 assertTrue(mMockAgent.mCountDownLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); 430 431 assertTrue(mMockAgent.mAddPlaylistItemCalled); 432 assertEquals(testIndex, mMockAgent.mIndex); 433 // MediaController2.addPlaylistItem does not ensure the equality of the items. 434 assertEquals(testMediaItem.getMediaId(), mMockAgent.mItem.getMediaId()); 435 } 436 437 @Test 438 public void testRemovePlaylistItem() throws InterruptedException { 439 prepareLooper(); 440 mMockAgent.mPlaylist = TestUtils.createPlaylist(2); 441 442 // Recreate controller for sending removePlaylistItem. 443 // It's easier to ensure that MediaController2.getPlaylist() returns the playlist from the 444 // agent. 445 MediaController2 controller = createController(mSession.getToken()); 446 MediaItem2 targetItem = controller.getPlaylist().get(0); 447 controller.removePlaylistItem(targetItem); 448 assertTrue(mMockAgent.mCountDownLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); 449 450 assertTrue(mMockAgent.mRemovePlaylistItemCalled); 451 assertEquals(targetItem, mMockAgent.mItem); 452 } 453 454 @Test 455 public void testReplacePlaylistItem() throws InterruptedException { 456 prepareLooper(); 457 final int testIndex = 12; 458 final MediaItem2 testMediaItem = TestUtils.createMediaItemWithMetadata(); 459 mController.replacePlaylistItem(testIndex, testMediaItem); 460 assertTrue(mMockAgent.mCountDownLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); 461 462 assertTrue(mMockAgent.mReplacePlaylistItemCalled); 463 // MediaController2.replacePlaylistItem does not ensure the equality of the items. 464 assertEquals(testMediaItem.getMediaId(), mMockAgent.mItem.getMediaId()); 465 } 466 467 @Test 468 public void testSkipToPreviousItem() throws InterruptedException { 469 prepareLooper(); 470 mController.skipToPreviousItem(); 471 assertTrue(mMockAgent.mCountDownLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); 472 assertTrue(mMockAgent.mSkipToPreviousItemCalled); 473 } 474 475 @Test 476 public void testSkipToNextItem() throws InterruptedException { 477 prepareLooper(); 478 mController.skipToNextItem(); 479 assertTrue(mMockAgent.mCountDownLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); 480 assertTrue(mMockAgent.mSkipToNextItemCalled); 481 } 482 483 @Test 484 public void testSkipToPlaylistItem() throws InterruptedException { 485 prepareLooper(); 486 MediaController2 controller = createController(mSession.getToken()); 487 MediaItem2 targetItem = TestUtils.createMediaItemWithMetadata(); 488 controller.skipToPlaylistItem(targetItem); 489 assertTrue(mMockAgent.mCountDownLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); 490 491 assertTrue(mMockAgent.mSkipToPlaylistItemCalled); 492 assertEquals(targetItem, mMockAgent.mItem); 493 } 494 495 /** 496 * This also tests {@link ControllerCallback#onShuffleModeChanged(MediaController2, int)}. 497 */ 498 @Test 499 public void testGetShuffleMode() throws InterruptedException { 500 prepareLooper(); 501 final int testShuffleMode = MediaPlaylistAgent.SHUFFLE_MODE_GROUP; 502 final MediaPlaylistAgent agent = new MockPlaylistAgent() { 503 @Override 504 public int getShuffleMode() { 505 return testShuffleMode; 506 } 507 }; 508 final CountDownLatch latch = new CountDownLatch(1); 509 final ControllerCallback callback = new ControllerCallback() { 510 @Override 511 public void onShuffleModeChanged(MediaController2 controller, int shuffleMode) { 512 assertEquals(testShuffleMode, shuffleMode); 513 latch.countDown(); 514 } 515 }; 516 mSession.updatePlayer(mPlayer, agent, null); 517 MediaController2 controller = createController(mSession.getToken(), true, callback); 518 agent.notifyShuffleModeChanged(); 519 assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); 520 assertEquals(testShuffleMode, controller.getShuffleMode()); 521 } 522 523 @Test 524 public void testSetShuffleMode() throws InterruptedException { 525 prepareLooper(); 526 final int testShuffleMode = MediaPlaylistAgent.SHUFFLE_MODE_GROUP; 527 mController.setShuffleMode(testShuffleMode); 528 assertTrue(mMockAgent.mCountDownLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); 529 530 assertTrue(mMockAgent.mSetShuffleModeCalled); 531 assertEquals(testShuffleMode, mMockAgent.mShuffleMode); 532 } 533 534 /** 535 * This also tests {@link ControllerCallback#onRepeatModeChanged(MediaController2, int)}. 536 */ 537 @Test 538 public void testGetRepeatMode() throws InterruptedException { 539 prepareLooper(); 540 final int testRepeatMode = MediaPlaylistAgent.REPEAT_MODE_GROUP; 541 final MediaPlaylistAgent agent = new MockPlaylistAgent() { 542 @Override 543 public int getRepeatMode() { 544 return testRepeatMode; 545 } 546 }; 547 final CountDownLatch latch = new CountDownLatch(1); 548 final ControllerCallback callback = new ControllerCallback() { 549 @Override 550 public void onRepeatModeChanged(MediaController2 controller, int repeatMode) { 551 assertEquals(testRepeatMode, repeatMode); 552 latch.countDown(); 553 } 554 }; 555 mSession.updatePlayer(mPlayer, agent, null); 556 MediaController2 controller = createController(mSession.getToken(), true, callback); 557 agent.notifyRepeatModeChanged(); 558 assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); 559 assertEquals(testRepeatMode, controller.getRepeatMode()); 560 } 561 562 @Test 563 public void testSetRepeatMode() throws InterruptedException { 564 prepareLooper(); 565 final int testRepeatMode = MediaPlaylistAgent.REPEAT_MODE_GROUP; 566 mController.setRepeatMode(testRepeatMode); 567 assertTrue(mMockAgent.mCountDownLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); 568 569 assertTrue(mMockAgent.mSetRepeatModeCalled); 570 assertEquals(testRepeatMode, mMockAgent.mRepeatMode); 571 } 572 573 @Test 574 public void testSetVolumeTo() throws Exception { 575 // TODO(jaewan): Also test with local volume. 576 prepareLooper(); 577 final int maxVolume = 100; 578 final int currentVolume = 23; 579 final int volumeControlType = VolumeProviderCompat.VOLUME_CONTROL_ABSOLUTE; 580 TestVolumeProvider volumeProvider = 581 new TestVolumeProvider(volumeControlType, maxVolume, currentVolume); 582 583 mSession.updatePlayer(new MockPlayer(0), null, volumeProvider); 584 final MediaController2 controller = createController(mSession.getToken(), true, null); 585 586 final int targetVolume = 50; 587 controller.setVolumeTo(targetVolume, 0 /* flags */); 588 assertTrue(volumeProvider.mLatch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS)); 589 assertTrue(volumeProvider.mSetVolumeToCalled); 590 assertEquals(targetVolume, volumeProvider.mVolume); 591 } 592 593 @Test 594 public void testAdjustVolume() throws Exception { 595 // TODO(jaewan): Also test with local volume. 596 prepareLooper(); 597 final int maxVolume = 100; 598 final int currentVolume = 23; 599 final int volumeControlType = VolumeProviderCompat.VOLUME_CONTROL_ABSOLUTE; 600 TestVolumeProvider volumeProvider = 601 new TestVolumeProvider(volumeControlType, maxVolume, currentVolume); 602 603 mSession.updatePlayer(new MockPlayer(0), null, volumeProvider); 604 final MediaController2 controller = createController(mSession.getToken(), true, null); 605 606 final int direction = AudioManager.ADJUST_RAISE; 607 controller.adjustVolume(direction, 0 /* flags */); 608 assertTrue(volumeProvider.mLatch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS)); 609 assertTrue(volumeProvider.mAdjustVolumeCalled); 610 assertEquals(direction, volumeProvider.mDirection); 611 } 612 613 @Test 614 public void testGetPackageName() { 615 prepareLooper(); 616 assertEquals(mContext.getPackageName(), mController.getSessionToken().getPackageName()); 617 } 618 619 @Test 620 public void testSendCustomCommand() throws InterruptedException { 621 prepareLooper(); 622 // TODO(jaewan): Need to revisit with the permission. 623 final SessionCommand2 testCommand = 624 new SessionCommand2(SessionCommand2.COMMAND_CODE_PLAYBACK_PREPARE); 625 final Bundle testArgs = new Bundle(); 626 testArgs.putString("args", "testSendCustomCommand"); 627 628 final CountDownLatch latch = new CountDownLatch(1); 629 final SessionCallback callback = new SessionCallback() { 630 @Override 631 public void onCustomCommand(MediaSession2 session, ControllerInfo controller, 632 SessionCommand2 customCommand, Bundle args, ResultReceiver cb) { 633 assertEquals(mContext.getPackageName(), controller.getPackageName()); 634 assertEquals(testCommand, customCommand); 635 assertTrue(TestUtils.equals(testArgs, args)); 636 assertNull(cb); 637 latch.countDown(); 638 } 639 }; 640 mSession.close(); 641 mSession = new MediaSession2.Builder(mContext).setPlayer(mPlayer) 642 .setSessionCallback(sHandlerExecutor, callback).setId(TAG).build(); 643 final MediaController2 controller = createController(mSession.getToken()); 644 controller.sendCustomCommand(testCommand, testArgs, null); 645 assertTrue(latch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS)); 646 } 647 648 @Test 649 public void testControllerCallback_onConnected() throws InterruptedException { 650 prepareLooper(); 651 // createController() uses controller callback to wait until the controller becomes 652 // available. 653 MediaController2 controller = createController(mSession.getToken()); 654 assertNotNull(controller); 655 } 656 657 @Test 658 public void testControllerCallback_sessionRejects() throws InterruptedException { 659 prepareLooper(); 660 final MediaSession2.SessionCallback sessionCallback = new SessionCallback() { 661 @Override 662 public SessionCommandGroup2 onConnect(MediaSession2 session, 663 ControllerInfo controller) { 664 return null; 665 } 666 }; 667 sHandler.postAndSync(new Runnable() { 668 @Override 669 public void run() { 670 mSession.close(); 671 mSession = new MediaSession2.Builder(mContext).setPlayer(mPlayer) 672 .setSessionCallback(sHandlerExecutor, sessionCallback).build(); 673 } 674 }); 675 MediaController2 controller = 676 createController(mSession.getToken(), false, null); 677 assertNotNull(controller); 678 waitForConnect(controller, false); 679 waitForDisconnect(controller, true); 680 } 681 682 @Test 683 public void testControllerCallback_releaseSession() throws InterruptedException { 684 prepareLooper(); 685 mSession.close(); 686 waitForDisconnect(mController, true); 687 } 688 689 @Test 690 public void testControllerCallback_close() throws InterruptedException { 691 prepareLooper(); 692 mController.close(); 693 waitForDisconnect(mController, true); 694 } 695 696 @Test 697 public void testFastForward() throws InterruptedException { 698 prepareLooper(); 699 final CountDownLatch latch = new CountDownLatch(1); 700 final SessionCallback callback = new SessionCallback() { 701 @Override 702 public void onFastForward(MediaSession2 session, ControllerInfo controller) { 703 assertEquals(mContext.getPackageName(), controller.getPackageName()); 704 latch.countDown(); 705 } 706 }; 707 try (MediaSession2 session = new MediaSession2.Builder(mContext) 708 .setPlayer(mPlayer) 709 .setSessionCallback(sHandlerExecutor, callback) 710 .setId("testFastForward").build()) { 711 MediaController2 controller = createController(session.getToken()); 712 controller.fastForward(); 713 assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); 714 } 715 } 716 717 @Test 718 public void testRewind() throws InterruptedException { 719 prepareLooper(); 720 final CountDownLatch latch = new CountDownLatch(1); 721 final SessionCallback callback = new SessionCallback() { 722 @Override 723 public void onRewind(MediaSession2 session, ControllerInfo controller) { 724 assertEquals(mContext.getPackageName(), controller.getPackageName()); 725 latch.countDown(); 726 } 727 }; 728 try (MediaSession2 session = new MediaSession2.Builder(mContext) 729 .setPlayer(mPlayer) 730 .setSessionCallback(sHandlerExecutor, callback) 731 .setId("testRewind").build()) { 732 MediaController2 controller = createController(session.getToken()); 733 controller.rewind(); 734 assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); 735 } 736 } 737 738 @Test 739 public void testPlayFromSearch() throws InterruptedException { 740 prepareLooper(); 741 final String request = "random query"; 742 final Bundle bundle = new Bundle(); 743 bundle.putString("key", "value"); 744 final CountDownLatch latch = new CountDownLatch(1); 745 final SessionCallback callback = new SessionCallback() { 746 @Override 747 public void onPlayFromSearch(MediaSession2 session, ControllerInfo controller, 748 String query, Bundle extras) { 749 super.onPlayFromSearch(session, controller, query, extras); 750 assertEquals(mContext.getPackageName(), controller.getPackageName()); 751 assertEquals(request, query); 752 assertTrue(TestUtils.equals(bundle, extras)); 753 latch.countDown(); 754 } 755 }; 756 try (MediaSession2 session = new MediaSession2.Builder(mContext) 757 .setPlayer(mPlayer) 758 .setSessionCallback(sHandlerExecutor, callback) 759 .setId("testPlayFromSearch").build()) { 760 MediaController2 controller = createController(session.getToken()); 761 controller.playFromSearch(request, bundle); 762 assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); 763 } 764 } 765 766 @Test 767 public void testPlayFromUri() throws InterruptedException { 768 prepareLooper(); 769 final Uri request = Uri.parse("foo://boo"); 770 final Bundle bundle = new Bundle(); 771 bundle.putString("key", "value"); 772 final CountDownLatch latch = new CountDownLatch(1); 773 final SessionCallback callback = new SessionCallback() { 774 @Override 775 public void onPlayFromUri(MediaSession2 session, ControllerInfo controller, Uri uri, 776 Bundle extras) { 777 assertEquals(mContext.getPackageName(), controller.getPackageName()); 778 assertEquals(request, uri); 779 assertTrue(TestUtils.equals(bundle, extras)); 780 latch.countDown(); 781 } 782 }; 783 try (MediaSession2 session = new MediaSession2.Builder(mContext) 784 .setPlayer(mPlayer) 785 .setSessionCallback(sHandlerExecutor, callback) 786 .setId("testPlayFromUri").build()) { 787 MediaController2 controller = createController(session.getToken()); 788 controller.playFromUri(request, bundle); 789 assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); 790 } 791 } 792 793 @Test 794 public void testPlayFromMediaId() throws InterruptedException { 795 prepareLooper(); 796 final String request = "media_id"; 797 final Bundle bundle = new Bundle(); 798 bundle.putString("key", "value"); 799 final CountDownLatch latch = new CountDownLatch(1); 800 final SessionCallback callback = new SessionCallback() { 801 @Override 802 public void onPlayFromMediaId(MediaSession2 session, ControllerInfo controller, 803 String mediaId, Bundle extras) { 804 assertEquals(mContext.getPackageName(), controller.getPackageName()); 805 assertEquals(request, mediaId); 806 assertTrue(TestUtils.equals(bundle, extras)); 807 latch.countDown(); 808 } 809 }; 810 try (MediaSession2 session = new MediaSession2.Builder(mContext) 811 .setPlayer(mPlayer) 812 .setSessionCallback(sHandlerExecutor, callback) 813 .setId("testPlayFromMediaId").build()) { 814 MediaController2 controller = createController(session.getToken()); 815 controller.playFromMediaId(request, bundle); 816 assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); 817 } 818 } 819 820 @Test 821 public void testPrepareFromSearch() throws InterruptedException { 822 prepareLooper(); 823 final String request = "random query"; 824 final Bundle bundle = new Bundle(); 825 bundle.putString("key", "value"); 826 final CountDownLatch latch = new CountDownLatch(1); 827 final SessionCallback callback = new SessionCallback() { 828 @Override 829 public void onPrepareFromSearch(MediaSession2 session, ControllerInfo controller, 830 String query, Bundle extras) { 831 assertEquals(mContext.getPackageName(), controller.getPackageName()); 832 assertEquals(request, query); 833 assertTrue(TestUtils.equals(bundle, extras)); 834 latch.countDown(); 835 } 836 }; 837 try (MediaSession2 session = new MediaSession2.Builder(mContext) 838 .setPlayer(mPlayer) 839 .setSessionCallback(sHandlerExecutor, callback) 840 .setId("testPrepareFromSearch").build()) { 841 MediaController2 controller = createController(session.getToken()); 842 controller.prepareFromSearch(request, bundle); 843 assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); 844 } 845 } 846 847 @Test 848 public void testPrepareFromUri() throws InterruptedException { 849 prepareLooper(); 850 final Uri request = Uri.parse("foo://boo"); 851 final Bundle bundle = new Bundle(); 852 bundle.putString("key", "value"); 853 final CountDownLatch latch = new CountDownLatch(1); 854 final SessionCallback callback = new SessionCallback() { 855 @Override 856 public void onPrepareFromUri(MediaSession2 session, ControllerInfo controller, Uri uri, 857 Bundle extras) { 858 assertEquals(mContext.getPackageName(), controller.getPackageName()); 859 assertEquals(request, uri); 860 assertTrue(TestUtils.equals(bundle, extras)); 861 latch.countDown(); 862 } 863 }; 864 try (MediaSession2 session = new MediaSession2.Builder(mContext) 865 .setPlayer(mPlayer) 866 .setSessionCallback(sHandlerExecutor, callback) 867 .setId("testPrepareFromUri").build()) { 868 MediaController2 controller = createController(session.getToken()); 869 controller.prepareFromUri(request, bundle); 870 assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); 871 } 872 } 873 874 @Test 875 public void testPrepareFromMediaId() throws InterruptedException { 876 prepareLooper(); 877 final String request = "media_id"; 878 final Bundle bundle = new Bundle(); 879 bundle.putString("key", "value"); 880 final CountDownLatch latch = new CountDownLatch(1); 881 final SessionCallback callback = new SessionCallback() { 882 @Override 883 public void onPrepareFromMediaId(MediaSession2 session, ControllerInfo controller, 884 String mediaId, Bundle extras) { 885 assertEquals(mContext.getPackageName(), controller.getPackageName()); 886 assertEquals(request, mediaId); 887 assertTrue(TestUtils.equals(bundle, extras)); 888 latch.countDown(); 889 } 890 }; 891 try (MediaSession2 session = new MediaSession2.Builder(mContext) 892 .setPlayer(mPlayer) 893 .setSessionCallback(sHandlerExecutor, callback) 894 .setId("testPrepareFromMediaId").build()) { 895 MediaController2 controller = createController(session.getToken()); 896 controller.prepareFromMediaId(request, bundle); 897 assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); 898 } 899 } 900 901 @Test 902 public void testSetRating() throws InterruptedException { 903 prepareLooper(); 904 final int ratingType = Rating2.RATING_5_STARS; 905 final float ratingValue = 3.5f; 906 final Rating2 rating = Rating2.newStarRating(ratingType, ratingValue); 907 final String mediaId = "media_id"; 908 909 final CountDownLatch latch = new CountDownLatch(1); 910 final SessionCallback callback = new SessionCallback() { 911 @Override 912 public void onSetRating(MediaSession2 session, ControllerInfo controller, 913 String mediaIdOut, Rating2 ratingOut) { 914 assertEquals(mContext.getPackageName(), controller.getPackageName()); 915 assertEquals(mediaId, mediaIdOut); 916 assertEquals(rating, ratingOut); 917 latch.countDown(); 918 } 919 }; 920 921 try (MediaSession2 session = new MediaSession2.Builder(mContext) 922 .setPlayer(mPlayer) 923 .setSessionCallback(sHandlerExecutor, callback) 924 .setId("testSetRating").build()) { 925 MediaController2 controller = createController(session.getToken()); 926 controller.setRating(mediaId, rating); 927 assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); 928 } 929 } 930 931 @Test 932 public void testIsConnected() throws InterruptedException { 933 prepareLooper(); 934 assertTrue(mController.isConnected()); 935 sHandler.postAndSync(new Runnable() { 936 @Override 937 public void run() { 938 mSession.close(); 939 } 940 }); 941 waitForDisconnect(mController, true); 942 assertFalse(mController.isConnected()); 943 } 944 945 /** 946 * Test potential deadlock for calls between controller and session. 947 */ 948 @Test 949 public void testDeadlock() throws InterruptedException { 950 prepareLooper(); 951 sHandler.postAndSync(new Runnable() { 952 @Override 953 public void run() { 954 mSession.close(); 955 mSession = null; 956 } 957 }); 958 959 // Two more threads are needed not to block test thread nor test wide thread (sHandler). 960 final HandlerThread sessionThread = new HandlerThread("testDeadlock_session"); 961 final HandlerThread testThread = new HandlerThread("testDeadlock_test"); 962 sessionThread.start(); 963 testThread.start(); 964 final SyncHandler sessionHandler = new SyncHandler(sessionThread.getLooper()); 965 final Handler testHandler = new Handler(testThread.getLooper()); 966 final CountDownLatch latch = new CountDownLatch(1); 967 try { 968 final MockPlayer player = new MockPlayer(0); 969 sessionHandler.postAndSync(new Runnable() { 970 @Override 971 public void run() { 972 mSession = new MediaSession2.Builder(mContext) 973 .setPlayer(mPlayer) 974 .setSessionCallback(sHandlerExecutor, new SessionCallback() {}) 975 .setId("testDeadlock").build(); 976 } 977 }); 978 final MediaController2 controller = createController(mSession.getToken()); 979 testHandler.post(new Runnable() { 980 @Override 981 public void run() { 982 final int state = MediaPlayerBase.PLAYER_STATE_ERROR; 983 for (int i = 0; i < 100; i++) { 984 // triggers call from session to controller. 985 player.notifyPlaybackState(state); 986 // triggers call from controller to session. 987 controller.play(); 988 989 // Repeat above 990 player.notifyPlaybackState(state); 991 controller.pause(); 992 player.notifyPlaybackState(state); 993 controller.reset(); 994 player.notifyPlaybackState(state); 995 controller.skipToNextItem(); 996 player.notifyPlaybackState(state); 997 controller.skipToPreviousItem(); 998 } 999 // This may hang if deadlock happens. 1000 latch.countDown(); 1001 } 1002 }); 1003 assertTrue(latch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS)); 1004 } finally { 1005 if (mSession != null) { 1006 sessionHandler.postAndSync(new Runnable() { 1007 @Override 1008 public void run() { 1009 // Clean up here because sessionHandler will be removed afterwards. 1010 mSession.close(); 1011 mSession = null; 1012 } 1013 }); 1014 } 1015 if (sessionThread != null) { 1016 sessionThread.quitSafely(); 1017 } 1018 if (testThread != null) { 1019 testThread.quitSafely(); 1020 } 1021 } 1022 } 1023 1024 @Test 1025 public void testGetServiceToken() { 1026 prepareLooper(); 1027 SessionToken2 token = TestUtils.getServiceToken(mContext, MockMediaSessionService2.ID); 1028 assertNotNull(token); 1029 assertEquals(mContext.getPackageName(), token.getPackageName()); 1030 assertEquals(MockMediaSessionService2.ID, token.getId()); 1031 assertEquals(SessionToken2.TYPE_SESSION_SERVICE, token.getType()); 1032 } 1033 1034 @Test 1035 public void testConnectToService_sessionService() throws InterruptedException { 1036 prepareLooper(); 1037 testConnectToService(MockMediaSessionService2.ID); 1038 } 1039 1040 @Test 1041 public void testConnectToService_libraryService() throws InterruptedException { 1042 prepareLooper(); 1043 testConnectToService(MockMediaLibraryService2.ID); 1044 } 1045 1046 public void testConnectToService(String id) throws InterruptedException { 1047 prepareLooper(); 1048 final CountDownLatch latch = new CountDownLatch(1); 1049 final MediaLibrarySessionCallback sessionCallback = new MediaLibrarySessionCallback() { 1050 @Override 1051 public SessionCommandGroup2 onConnect(@NonNull MediaSession2 session, 1052 @NonNull ControllerInfo controller) { 1053 if (Process.myUid() == controller.getUid()) { 1054 if (mSession != null) { 1055 mSession.close(); 1056 } 1057 mSession = session; 1058 mPlayer = (MockPlayer) session.getPlayer(); 1059 assertEquals(mContext.getPackageName(), controller.getPackageName()); 1060 assertFalse(controller.isTrusted()); 1061 latch.countDown(); 1062 } 1063 return super.onConnect(session, controller); 1064 } 1065 }; 1066 TestServiceRegistry.getInstance().setSessionCallback(sessionCallback); 1067 1068 final SessionCommand2 testCommand = new SessionCommand2("testConnectToService", null); 1069 final CountDownLatch controllerLatch = new CountDownLatch(1); 1070 mController = createController(TestUtils.getServiceToken(mContext, id), true, 1071 new ControllerCallback() { 1072 @Override 1073 public void onCustomCommand(MediaController2 controller, 1074 SessionCommand2 command, Bundle args, ResultReceiver receiver) { 1075 if (testCommand.equals(command)) { 1076 controllerLatch.countDown(); 1077 } 1078 } 1079 } 1080 ); 1081 assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); 1082 1083 // Test command from controller to session service. 1084 mController.play(); 1085 assertTrue(mPlayer.mCountDownLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); 1086 assertTrue(mPlayer.mPlayCalled); 1087 1088 // Test command from session service to controller. 1089 mSession.sendCustomCommand(testCommand, null); 1090 assertTrue(controllerLatch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS)); 1091 } 1092 1093 @Test 1094 public void testControllerAfterSessionIsGone_session() throws InterruptedException { 1095 prepareLooper(); 1096 testControllerAfterSessionIsClosed(mSession.getToken().getId()); 1097 } 1098 1099 // TODO(jaewan): Re-enable this test 1100 @Ignore 1101 @Test 1102 public void testControllerAfterSessionIsClosed_sessionService() throws InterruptedException { 1103 prepareLooper(); 1104 /* 1105 connectToService(TestUtils.getServiceToken(mContext, MockMediaSessionService2.ID)); 1106 testControllerAfterSessionIsClosed(MockMediaSessionService2.ID); 1107 */ 1108 } 1109 1110 @Test 1111 public void testSubscribeRouteInfo() throws InterruptedException { 1112 prepareLooper(); 1113 final TestSessionCallback callback = new TestSessionCallback() { 1114 @Override 1115 public void onSubscribeRoutesInfo(@NonNull MediaSession2 session, 1116 @NonNull ControllerInfo controller) { 1117 assertEquals(mContext.getPackageName(), controller.getPackageName()); 1118 mLatch.countDown(); 1119 } 1120 1121 @Override 1122 public void onUnsubscribeRoutesInfo(@NonNull MediaSession2 session, 1123 @NonNull ControllerInfo controller) { 1124 assertEquals(mContext.getPackageName(), controller.getPackageName()); 1125 mLatch.countDown(); 1126 } 1127 }; 1128 mSession.close(); 1129 mSession = new MediaSession2.Builder(mContext).setPlayer(mPlayer) 1130 .setSessionCallback(sHandlerExecutor, callback).setId(TAG).build(); 1131 final MediaController2 controller = createController(mSession.getToken()); 1132 1133 callback.resetLatchCount(1); 1134 controller.subscribeRoutesInfo(); 1135 assertTrue(callback.mLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); 1136 1137 callback.resetLatchCount(1); 1138 controller.unsubscribeRoutesInfo(); 1139 assertTrue(callback.mLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); 1140 } 1141 1142 @Test 1143 public void testSelectRouteInfo() throws InterruptedException { 1144 prepareLooper(); 1145 final Bundle testRoute = new Bundle(); 1146 testRoute.putString("id", "testRoute"); 1147 final TestSessionCallback callback = new TestSessionCallback() { 1148 @Override 1149 public void onSelectRoute(@NonNull MediaSession2 session, 1150 @NonNull ControllerInfo controller, @NonNull Bundle route) { 1151 assertEquals(mContext.getPackageName(), controller.getPackageName()); 1152 assertTrue(TestUtils.equals(route, testRoute)); 1153 mLatch.countDown(); 1154 } 1155 }; 1156 mSession.close(); 1157 mSession = new MediaSession2.Builder(mContext).setPlayer(mPlayer) 1158 .setSessionCallback(sHandlerExecutor, callback).setId(TAG).build(); 1159 final MediaController2 controller = createController(mSession.getToken()); 1160 1161 callback.resetLatchCount(1); 1162 controller.selectRoute(testRoute); 1163 assertTrue(callback.mLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); 1164 } 1165 1166 @Test 1167 public void testClose_beforeConnected() throws InterruptedException { 1168 prepareLooper(); 1169 MediaController2 controller = 1170 createController(mSession.getToken(), false, null); 1171 controller.close(); 1172 } 1173 1174 @Test 1175 public void testClose_twice() { 1176 prepareLooper(); 1177 mController.close(); 1178 mController.close(); 1179 } 1180 1181 @Test 1182 public void testClose_session() throws InterruptedException { 1183 prepareLooper(); 1184 final String id = mSession.getToken().getId(); 1185 mController.close(); 1186 // close is done immediately for session. 1187 testNoInteraction(); 1188 1189 // Test whether the controller is notified about later close of the session or 1190 // re-creation. 1191 testControllerAfterSessionIsClosed(id); 1192 } 1193 1194 @Ignore 1195 @Test 1196 public void testClose_sessionService() throws InterruptedException { 1197 prepareLooper(); 1198 testCloseFromService(MockMediaSessionService2.ID); 1199 } 1200 1201 @Ignore 1202 @Test 1203 public void testClose_libraryService() throws InterruptedException { 1204 prepareLooper(); 1205 testCloseFromService(MockMediaLibraryService2.ID); 1206 } 1207 1208 private void testCloseFromService(String id) throws InterruptedException { 1209 final CountDownLatch latch = new CountDownLatch(1); 1210 TestServiceRegistry.getInstance().setSessionServiceCallback(new SessionServiceCallback() { 1211 @Override 1212 public void onCreated() { 1213 // Do nothing. 1214 } 1215 1216 @Override 1217 public void onDestroyed() { 1218 latch.countDown(); 1219 } 1220 }); 1221 mController = createController(TestUtils.getServiceToken(mContext, id)); 1222 mController.close(); 1223 // Wait until close triggers onDestroy() of the session service. 1224 assertTrue(latch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS)); 1225 assertNull(TestServiceRegistry.getInstance().getServiceInstance()); 1226 testNoInteraction(); 1227 1228 // Test whether the controller is notified about later close of the session or 1229 // re-creation. 1230 testControllerAfterSessionIsClosed(id); 1231 } 1232 1233 private void testControllerAfterSessionIsClosed(final String id) throws InterruptedException { 1234 // This cause session service to be died. 1235 mSession.close(); 1236 waitForDisconnect(mController, true); 1237 testNoInteraction(); 1238 1239 // Ensure that the controller cannot use newly create session with the same ID. 1240 // Recreated session has different session stub, so previously created controller 1241 // shouldn't be available. 1242 mSession = new MediaSession2.Builder(mContext) 1243 .setPlayer(mPlayer) 1244 .setSessionCallback(sHandlerExecutor, new SessionCallback() {}) 1245 .setId(id).build(); 1246 testNoInteraction(); 1247 } 1248 1249 // Test that mSession and mController doesn't interact. 1250 // Note that this method can be called after the mSession is died, so mSession may not have 1251 // valid player. 1252 private void testNoInteraction() throws InterruptedException { 1253 // TODO: check that calls from the controller to session shouldn't be delivered. 1254 1255 // Calls from the session to controller shouldn't be delivered. 1256 final CountDownLatch latch = new CountDownLatch(1); 1257 setRunnableForOnCustomCommand(mController, new Runnable() { 1258 @Override 1259 public void run() { 1260 latch.countDown(); 1261 } 1262 }); 1263 SessionCommand2 customCommand = new SessionCommand2("testNoInteraction", null); 1264 mSession.sendCustomCommand(customCommand, null); 1265 assertFalse(latch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS)); 1266 setRunnableForOnCustomCommand(mController, null); 1267 } 1268 1269 // TODO(jaewan): Add test for service connect rejection, when we differentiate session 1270 // active/inactive and connection accept/refuse 1271 1272 class TestVolumeProvider extends VolumeProviderCompat { 1273 final CountDownLatch mLatch = new CountDownLatch(1); 1274 boolean mSetVolumeToCalled; 1275 boolean mAdjustVolumeCalled; 1276 int mVolume; 1277 int mDirection; 1278 1279 TestVolumeProvider(int controlType, int maxVolume, int currentVolume) { 1280 super(controlType, maxVolume, currentVolume); 1281 } 1282 1283 @Override 1284 public void onSetVolumeTo(int volume) { 1285 mSetVolumeToCalled = true; 1286 mVolume = volume; 1287 mLatch.countDown(); 1288 } 1289 1290 @Override 1291 public void onAdjustVolume(int direction) { 1292 mAdjustVolumeCalled = true; 1293 mDirection = direction; 1294 mLatch.countDown(); 1295 } 1296 } 1297 1298 class TestSessionCallback extends SessionCallback { 1299 CountDownLatch mLatch; 1300 1301 void resetLatchCount(int count) { 1302 mLatch = new CountDownLatch(count); 1303 } 1304 } 1305} 1306