1 /* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package android.media.cts; 17 18 import static android.media.AudioAttributes.USAGE_GAME; 19 import static android.media.cts.MediaSessionTestService.KEY_EXPECTED_QUEUE_SIZE; 20 import static android.media.cts.MediaSessionTestService.KEY_EXPECTED_TOTAL_NUMBER_OF_ITEMS; 21 import static android.media.cts.MediaSessionTestService.KEY_SESSION_TOKEN; 22 import static android.media.cts.MediaSessionTestService.STEP_CHECK; 23 import static android.media.cts.MediaSessionTestService.STEP_CLEAN_UP; 24 import static android.media.cts.MediaSessionTestService.STEP_SET_UP; 25 import static android.media.cts.MediaSessionTestService.TEST_SERIES_OF_SET_QUEUE; 26 import static android.media.cts.MediaSessionTestService.TEST_SET_QUEUE; 27 import static android.media.cts.Utils.compareRemoteUserInfo; 28 29 import android.app.PendingIntent; 30 import android.content.ComponentName; 31 import android.content.Context; 32 import android.content.Intent; 33 import android.media.AudioAttributes; 34 import android.media.AudioManager; 35 import android.media.MediaDescription; 36 import android.media.MediaMetadata; 37 import android.media.MediaSession2; 38 import android.media.Rating; 39 import android.media.VolumeProvider; 40 import android.media.session.MediaController; 41 import android.media.session.MediaSession; 42 import android.media.session.MediaSession.QueueItem; 43 import android.media.session.MediaSessionManager; 44 import android.media.session.MediaSessionManager.RemoteUserInfo; 45 import android.media.session.PlaybackState; 46 import android.os.Bundle; 47 import android.os.Handler; 48 import android.os.Looper; 49 import android.os.Parcel; 50 import android.os.Process; 51 import android.platform.test.annotations.AppModeFull; 52 import android.test.AndroidTestCase; 53 import android.text.TextUtils; 54 import android.view.KeyEvent; 55 56 import java.util.ArrayList; 57 import java.util.Collections; 58 import java.util.List; 59 import java.util.concurrent.CountDownLatch; 60 import java.util.concurrent.TimeUnit; 61 62 @NonMediaMainlineTest 63 @AppModeFull(reason = "TODO: evaluate and port to instant") 64 public class MediaSessionTest extends AndroidTestCase { 65 // The maximum time to wait for an operation that is expected to succeed. 66 private static final long TIME_OUT_MS = 3000L; 67 // The maximum time to wait for an operation that is expected to fail. 68 private static final long WAIT_MS = 100L; 69 private static final int MAX_AUDIO_INFO_CHANGED_CALLBACK_COUNT = 10; 70 private static final String TEST_SESSION_TAG = "test-session-tag"; 71 private static final String TEST_KEY = "test-key"; 72 private static final String TEST_VALUE = "test-val"; 73 private static final String TEST_SESSION_EVENT = "test-session-event"; 74 private static final String TEST_VOLUME_CONTROL_ID = "test-volume-control-id"; 75 private static final int TEST_CURRENT_VOLUME = 10; 76 private static final int TEST_MAX_VOLUME = 11; 77 private static final long TEST_QUEUE_ID = 12L; 78 private static final long TEST_ACTION = 55L; 79 private static final int TEST_TOO_MANY_SESSION_COUNT = 1000; 80 81 private AudioManager mAudioManager; 82 private Handler mHandler = new Handler(Looper.getMainLooper()); 83 private Object mWaitLock = new Object(); 84 private MediaControllerCallback mCallback = new MediaControllerCallback(); 85 private MediaSession mSession; 86 private RemoteUserInfo mKeyDispatcherInfo; 87 88 @Override setUp()89 protected void setUp() throws Exception { 90 super.setUp(); 91 mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE); 92 mSession = new MediaSession(getContext(), TEST_SESSION_TAG); 93 mKeyDispatcherInfo = new MediaSessionManager.RemoteUserInfo( 94 getContext().getPackageName(), Process.myPid(), Process.myUid()); 95 } 96 97 @Override tearDown()98 protected void tearDown() throws Exception { 99 // It is OK to call release() twice. 100 if (mSession != null) { 101 mSession.release(); 102 mSession = null; 103 } 104 super.tearDown(); 105 } 106 107 /** 108 * Tests that a session can be created and that all the fields are 109 * initialized correctly. 110 */ testCreateSession()111 public void testCreateSession() throws Exception { 112 assertNotNull(mSession.getSessionToken()); 113 assertFalse("New session should not be active", mSession.isActive()); 114 115 // Verify by getting the controller and checking all its fields 116 MediaController controller = mSession.getController(); 117 assertNotNull(controller); 118 verifyNewSession(controller); 119 } 120 testSessionTokenEquals()121 public void testSessionTokenEquals() { 122 MediaSession anotherSession = null; 123 try { 124 anotherSession = new MediaSession(getContext(), TEST_SESSION_TAG); 125 MediaSession.Token sessionToken = mSession.getSessionToken(); 126 MediaSession.Token anotherSessionToken = anotherSession.getSessionToken(); 127 128 assertTrue(sessionToken.equals(sessionToken)); 129 assertFalse(sessionToken.equals(null)); 130 assertFalse(sessionToken.equals(mSession)); 131 assertFalse(sessionToken.equals(anotherSessionToken)); 132 } finally { 133 if (anotherSession != null) { 134 anotherSession.release(); 135 } 136 } 137 } 138 139 /** 140 * Tests MediaSession.Token created in the constructor of MediaSession. 141 */ testSessionToken()142 public void testSessionToken() throws Exception { 143 MediaSession.Token sessionToken = mSession.getSessionToken(); 144 145 assertNotNull(sessionToken); 146 assertEquals(0, sessionToken.describeContents()); 147 148 // Test writeToParcel 149 Parcel p = Parcel.obtain(); 150 sessionToken.writeToParcel(p, 0); 151 p.setDataPosition(0); 152 MediaSession.Token tokenFromParcel = MediaSession.Token.CREATOR.createFromParcel(p); 153 assertEquals(tokenFromParcel, sessionToken); 154 p.recycle(); 155 156 final int arraySize = 5; 157 MediaSession.Token[] tokenArray = MediaSession.Token.CREATOR.newArray(arraySize); 158 assertNotNull(tokenArray); 159 assertEquals(arraySize, tokenArray.length); 160 for (MediaSession.Token tokenElement : tokenArray) { 161 assertNull(tokenElement); 162 } 163 } 164 165 /** 166 * Tests that the various configuration bits on a session get passed to the 167 * controller. 168 */ testConfigureSession()169 public void testConfigureSession() throws Exception { 170 MediaController controller = mSession.getController(); 171 controller.registerCallback(mCallback, mHandler); 172 final MediaController.Callback callback = (MediaController.Callback) mCallback; 173 174 synchronized (mWaitLock) { 175 // test setExtras 176 mCallback.resetLocked(); 177 final Bundle extras = new Bundle(); 178 extras.putString(TEST_KEY, TEST_VALUE); 179 mSession.setExtras(extras); 180 mWaitLock.wait(TIME_OUT_MS); 181 assertTrue(mCallback.mOnExtraChangedCalled); 182 // just call the callback once directly so it's marked as tested 183 callback.onExtrasChanged(mCallback.mExtras); 184 185 Bundle extrasOut = mCallback.mExtras; 186 assertNotNull(extrasOut); 187 assertEquals(TEST_VALUE, extrasOut.get(TEST_KEY)); 188 189 extrasOut = controller.getExtras(); 190 assertNotNull(extrasOut); 191 assertEquals(TEST_VALUE, extrasOut.get(TEST_KEY)); 192 193 // test setFlags 194 mSession.setFlags(5); 195 assertEquals(5, controller.getFlags()); 196 197 // test setMetadata 198 mCallback.resetLocked(); 199 MediaMetadata metadata = 200 new MediaMetadata.Builder().putString(TEST_KEY, TEST_VALUE).build(); 201 mSession.setMetadata(metadata); 202 mWaitLock.wait(TIME_OUT_MS); 203 assertTrue(mCallback.mOnMetadataChangedCalled); 204 // just call the callback once directly so it's marked as tested 205 callback.onMetadataChanged(mCallback.mMediaMetadata); 206 207 MediaMetadata metadataOut = mCallback.mMediaMetadata; 208 assertNotNull(metadataOut); 209 assertEquals(TEST_VALUE, metadataOut.getString(TEST_KEY)); 210 211 metadataOut = controller.getMetadata(); 212 assertNotNull(metadataOut); 213 assertEquals(TEST_VALUE, metadataOut.getString(TEST_KEY)); 214 215 // test setPlaybackState 216 mCallback.resetLocked(); 217 PlaybackState state = new PlaybackState.Builder().setActions(TEST_ACTION).build(); 218 mSession.setPlaybackState(state); 219 mWaitLock.wait(TIME_OUT_MS); 220 assertTrue(mCallback.mOnPlaybackStateChangedCalled); 221 // just call the callback once directly so it's marked as tested 222 callback.onPlaybackStateChanged(mCallback.mPlaybackState); 223 224 PlaybackState stateOut = mCallback.mPlaybackState; 225 assertNotNull(stateOut); 226 assertEquals(TEST_ACTION, stateOut.getActions()); 227 228 stateOut = controller.getPlaybackState(); 229 assertNotNull(stateOut); 230 assertEquals(TEST_ACTION, stateOut.getActions()); 231 232 // test setQueue and setQueueTitle 233 mCallback.resetLocked(); 234 List<QueueItem> queue = new ArrayList<>(); 235 QueueItem item = new QueueItem(new MediaDescription.Builder() 236 .setMediaId(TEST_VALUE).setTitle("title").build(), TEST_QUEUE_ID); 237 queue.add(item); 238 mSession.setQueue(queue); 239 mWaitLock.wait(TIME_OUT_MS); 240 assertTrue(mCallback.mOnQueueChangedCalled); 241 // just call the callback once directly so it's marked as tested 242 callback.onQueueChanged(mCallback.mQueue); 243 244 mSession.setQueueTitle(TEST_VALUE); 245 mWaitLock.wait(TIME_OUT_MS); 246 assertTrue(mCallback.mOnQueueTitleChangedCalled); 247 248 assertEquals(TEST_VALUE, mCallback.mTitle); 249 assertEquals(queue.size(), mCallback.mQueue.size()); 250 assertEquals(TEST_QUEUE_ID, mCallback.mQueue.get(0).getQueueId()); 251 assertEquals(TEST_VALUE, mCallback.mQueue.get(0).getDescription().getMediaId()); 252 253 assertEquals(TEST_VALUE, controller.getQueueTitle()); 254 assertEquals(queue.size(), controller.getQueue().size()); 255 assertEquals(TEST_QUEUE_ID, controller.getQueue().get(0).getQueueId()); 256 assertEquals(TEST_VALUE, controller.getQueue().get(0).getDescription().getMediaId()); 257 258 mCallback.resetLocked(); 259 mSession.setQueue(null); 260 mWaitLock.wait(TIME_OUT_MS); 261 assertTrue(mCallback.mOnQueueChangedCalled); 262 // just call the callback once directly so it's marked as tested 263 callback.onQueueChanged(mCallback.mQueue); 264 265 mSession.setQueueTitle(null); 266 mWaitLock.wait(TIME_OUT_MS); 267 assertTrue(mCallback.mOnQueueTitleChangedCalled); 268 // just call the callback once directly so it's marked as tested 269 callback.onQueueTitleChanged(mCallback.mTitle); 270 271 assertNull(mCallback.mTitle); 272 assertNull(mCallback.mQueue); 273 assertNull(controller.getQueueTitle()); 274 assertNull(controller.getQueue()); 275 276 // test setSessionActivity 277 Intent intent = new Intent("cts.MEDIA_SESSION_ACTION"); 278 PendingIntent pi = PendingIntent.getActivity(getContext(), 555, intent, 279 PendingIntent.FLAG_MUTABLE_UNAUDITED); 280 mSession.setSessionActivity(pi); 281 assertEquals(pi, controller.getSessionActivity()); 282 283 // test setActivity 284 mSession.setActive(true); 285 assertTrue(mSession.isActive()); 286 287 // test sendSessionEvent 288 mCallback.resetLocked(); 289 mSession.sendSessionEvent(TEST_SESSION_EVENT, extras); 290 mWaitLock.wait(TIME_OUT_MS); 291 292 assertTrue(mCallback.mOnSessionEventCalled); 293 assertEquals(TEST_SESSION_EVENT, mCallback.mEvent); 294 assertEquals(TEST_VALUE, mCallback.mExtras.getString(TEST_KEY)); 295 // just call the callback once directly so it's marked as tested 296 callback.onSessionEvent(mCallback.mEvent, mCallback.mExtras); 297 298 // test release 299 mCallback.resetLocked(); 300 mSession.release(); 301 mWaitLock.wait(TIME_OUT_MS); 302 assertTrue(mCallback.mOnSessionDestroyedCalled); 303 // just call the callback once directly so it's marked as tested 304 callback.onSessionDestroyed(); 305 } 306 } 307 308 /** 309 * Test whether media button receiver can be a explicit broadcast receiver via 310 * MediaSession.setMediaButtonReceiver(PendingIntent). 311 */ testSetMediaButtonReceiver_broadcastReceiver()312 public void testSetMediaButtonReceiver_broadcastReceiver() throws Exception { 313 Intent intent = new Intent(mContext.getApplicationContext(), 314 MediaButtonBroadcastReceiver.class); 315 PendingIntent pi = PendingIntent.getBroadcast(mContext, 0, intent, 316 PendingIntent.FLAG_MUTABLE_UNAUDITED); 317 318 // Play a sound so this session can get the priority. 319 Utils.assertMediaPlaybackStarted(getContext()); 320 321 // Sets the media button receiver. Framework will keep the broadcast receiver component name 322 // from the pending intent in persistent storage. 323 mSession.setMediaButtonReceiver(pi); 324 325 // Call explicit release, so change in the media key event session can be notified with the 326 // pending intent. 327 mSession.release(); 328 329 int keyCode = KeyEvent.KEYCODE_MEDIA_PLAY; 330 try { 331 CountDownLatch latch = new CountDownLatch(2); 332 MediaButtonBroadcastReceiver.setCallback((keyEvent) -> { 333 assertEquals(keyCode, keyEvent.getKeyCode()); 334 switch ((int) latch.getCount()) { 335 case 2: 336 assertEquals(KeyEvent.ACTION_DOWN, keyEvent.getAction()); 337 break; 338 case 1: 339 assertEquals(KeyEvent.ACTION_UP, keyEvent.getAction()); 340 break; 341 } 342 latch.countDown(); 343 }); 344 // Also try to dispatch media key event. 345 // System would try to dispatch event. 346 simulateMediaKeyInput(keyCode); 347 348 assertTrue(latch.await(TIME_OUT_MS, TimeUnit.MILLISECONDS)); 349 } finally { 350 MediaButtonBroadcastReceiver.setCallback(null); 351 } 352 } 353 354 /** 355 * Test whether media button receiver can be a explicit service. 356 */ testSetMediaButtonReceiver_service()357 public void testSetMediaButtonReceiver_service() throws Exception { 358 Intent intent = new Intent(mContext.getApplicationContext(), 359 MediaButtonReceiverService.class); 360 PendingIntent pi = PendingIntent.getService(mContext, 0, intent, 361 PendingIntent.FLAG_MUTABLE_UNAUDITED); 362 363 // Play a sound so this session can get the priority. 364 Utils.assertMediaPlaybackStarted(getContext()); 365 366 // Sets the media button receiver. Framework would try to keep the pending intent in the 367 // persistent store. 368 mSession.setMediaButtonReceiver(pi); 369 370 // Call explicit release, so change in the media key event session can be notified with the 371 // pending intent. 372 mSession.release(); 373 374 int keyCode = KeyEvent.KEYCODE_MEDIA_PLAY; 375 try { 376 CountDownLatch latch = new CountDownLatch(2); 377 MediaButtonReceiverService.setCallback((keyEvent) -> { 378 assertEquals(keyCode, keyEvent.getKeyCode()); 379 switch ((int) latch.getCount()) { 380 case 2: 381 assertEquals(KeyEvent.ACTION_DOWN, keyEvent.getAction()); 382 break; 383 case 1: 384 assertEquals(KeyEvent.ACTION_UP, keyEvent.getAction()); 385 break; 386 } 387 latch.countDown(); 388 }); 389 // Also try to dispatch media key event. 390 // System would try to dispatch event. 391 simulateMediaKeyInput(keyCode); 392 393 assertTrue(latch.await(TIME_OUT_MS, TimeUnit.MILLISECONDS)); 394 } finally { 395 MediaButtonReceiverService.setCallback(null); 396 } 397 } 398 399 /** 400 * Test whether system doesn't crash by 401 * {@link MediaSession#setMediaButtonReceiver(PendingIntent)} with implicit intent. 402 */ testSetMediaButtonReceiver_implicitIntent()403 public void testSetMediaButtonReceiver_implicitIntent() throws Exception { 404 // Note: No such broadcast receiver exists. 405 Intent intent = new Intent("android.media.cts.ACTION_MEDIA_TEST"); 406 PendingIntent pi = PendingIntent.getBroadcast(mContext, 0, intent, 407 PendingIntent.FLAG_MUTABLE_UNAUDITED); 408 409 // Play a sound so this session can get the priority. 410 Utils.assertMediaPlaybackStarted(getContext()); 411 412 // Sets the media button receiver. Framework would try to keep the pending intent in the 413 // persistent store. 414 mSession.setMediaButtonReceiver(pi); 415 416 // Call explicit release, so change in the media key event session can be notified with the 417 // pending intent. 418 mSession.release(); 419 420 // Also try to dispatch media key event. System would try to send key event via pending 421 // intent, but it would no-op because there's no receiver. 422 simulateMediaKeyInput(KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE); 423 } 424 425 /** 426 * Test whether media button receiver can be a explicit broadcast receiver via 427 * MediaSession.setMediaButtonBroadcastReceiver(ComponentName) 428 */ testSetMediaButtonBroadcastReceiver_broadcastReceiver()429 public void testSetMediaButtonBroadcastReceiver_broadcastReceiver() throws Exception { 430 // Play a sound so this session can get the priority. 431 Utils.assertMediaPlaybackStarted(getContext()); 432 433 // Sets the broadcast receiver's component name. Framework will keep the component name in 434 // persistent storage. 435 mSession.setMediaButtonBroadcastReceiver(new ComponentName(mContext, 436 MediaButtonBroadcastReceiver.class)); 437 438 // Call explicit release, so change in the media key event session can be notified using the 439 // component name. 440 mSession.release(); 441 442 int keyCode = KeyEvent.KEYCODE_MEDIA_PLAY; 443 try { 444 CountDownLatch latch = new CountDownLatch(2); 445 MediaButtonBroadcastReceiver.setCallback((keyEvent) -> { 446 assertEquals(keyCode, keyEvent.getKeyCode()); 447 switch ((int) latch.getCount()) { 448 case 2: 449 assertEquals(KeyEvent.ACTION_DOWN, keyEvent.getAction()); 450 break; 451 case 1: 452 assertEquals(KeyEvent.ACTION_UP, keyEvent.getAction()); 453 break; 454 } 455 latch.countDown(); 456 }); 457 // Also try to dispatch media key event. 458 // System would try to dispatch event. 459 simulateMediaKeyInput(keyCode); 460 461 assertTrue(latch.await(TIME_OUT_MS, TimeUnit.MILLISECONDS)); 462 } finally { 463 MediaButtonBroadcastReceiver.setCallback(null); 464 } 465 } 466 467 /** 468 * Test public APIs of {@link VolumeProvider}. 469 */ testVolumeProvider()470 public void testVolumeProvider() { 471 VolumeProvider vp = new VolumeProvider(VolumeProvider.VOLUME_CONTROL_RELATIVE, 472 TEST_MAX_VOLUME, TEST_CURRENT_VOLUME, TEST_VOLUME_CONTROL_ID) {}; 473 assertEquals(VolumeProvider.VOLUME_CONTROL_RELATIVE, vp.getVolumeControl()); 474 assertEquals(TEST_MAX_VOLUME, vp.getMaxVolume()); 475 assertEquals(TEST_CURRENT_VOLUME, vp.getCurrentVolume()); 476 assertEquals(TEST_VOLUME_CONTROL_ID, vp.getVolumeControlId()); 477 } 478 479 /** 480 * Test {@link MediaSession#setPlaybackToLocal} and {@link MediaSession#setPlaybackToRemote}. 481 */ testPlaybackToLocalAndRemote()482 public void testPlaybackToLocalAndRemote() throws Exception { 483 MediaController controller = mSession.getController(); 484 controller.registerCallback(mCallback, mHandler); 485 486 synchronized (mWaitLock) { 487 // test setPlaybackToRemote, do this before testing setPlaybackToLocal 488 // to ensure it switches correctly. 489 mCallback.resetLocked(); 490 try { 491 mSession.setPlaybackToRemote(null); 492 fail("Expected IAE for setPlaybackToRemote(null)"); 493 } catch (IllegalArgumentException e) { 494 // expected 495 } 496 VolumeProvider vp = new VolumeProvider(VolumeProvider.VOLUME_CONTROL_FIXED, 497 TEST_MAX_VOLUME, TEST_CURRENT_VOLUME, TEST_VOLUME_CONTROL_ID) {}; 498 mSession.setPlaybackToRemote(vp); 499 500 MediaController.PlaybackInfo info = null; 501 for (int i = 0; i < MAX_AUDIO_INFO_CHANGED_CALLBACK_COUNT; ++i) { 502 mCallback.mOnAudioInfoChangedCalled = false; 503 mWaitLock.wait(TIME_OUT_MS); 504 assertTrue(mCallback.mOnAudioInfoChangedCalled); 505 info = mCallback.mPlaybackInfo; 506 if (info != null && info.getCurrentVolume() == TEST_CURRENT_VOLUME 507 && info.getMaxVolume() == TEST_MAX_VOLUME 508 && info.getVolumeControl() == VolumeProvider.VOLUME_CONTROL_FIXED 509 && info.getPlaybackType() 510 == MediaController.PlaybackInfo.PLAYBACK_TYPE_REMOTE 511 && TextUtils.equals(info.getVolumeControlId(),TEST_VOLUME_CONTROL_ID)) { 512 break; 513 } 514 } 515 assertNotNull(info); 516 assertEquals(MediaController.PlaybackInfo.PLAYBACK_TYPE_REMOTE, info.getPlaybackType()); 517 assertEquals(TEST_MAX_VOLUME, info.getMaxVolume()); 518 assertEquals(TEST_CURRENT_VOLUME, info.getCurrentVolume()); 519 assertEquals(VolumeProvider.VOLUME_CONTROL_FIXED, info.getVolumeControl()); 520 assertEquals(TEST_VOLUME_CONTROL_ID, info.getVolumeControlId()); 521 522 info = controller.getPlaybackInfo(); 523 assertNotNull(info); 524 assertEquals(MediaController.PlaybackInfo.PLAYBACK_TYPE_REMOTE, info.getPlaybackType()); 525 assertEquals(TEST_MAX_VOLUME, info.getMaxVolume()); 526 assertEquals(TEST_CURRENT_VOLUME, info.getCurrentVolume()); 527 assertEquals(VolumeProvider.VOLUME_CONTROL_FIXED, info.getVolumeControl()); 528 assertEquals(TEST_VOLUME_CONTROL_ID, info.getVolumeControlId()); 529 530 // test setPlaybackToLocal 531 AudioAttributes attrs = new AudioAttributes.Builder().setUsage(USAGE_GAME).build(); 532 mSession.setPlaybackToLocal(attrs); 533 534 info = controller.getPlaybackInfo(); 535 assertNotNull(info); 536 assertEquals(MediaController.PlaybackInfo.PLAYBACK_TYPE_LOCAL, info.getPlaybackType()); 537 assertEquals(attrs, info.getAudioAttributes()); 538 assertNull(info.getVolumeControlId()); 539 } 540 } 541 542 /** 543 * Test {@link MediaSession.Callback#onMediaButtonEvent}. 544 */ testCallbackOnMediaButtonEvent()545 public void testCallbackOnMediaButtonEvent() throws Exception { 546 MediaSessionCallback sessionCallback = new MediaSessionCallback(); 547 mSession.setCallback(sessionCallback, new Handler(Looper.getMainLooper())); 548 mSession.setFlags(MediaSession.FLAG_HANDLES_MEDIA_BUTTONS); 549 mSession.setActive(true); 550 551 // Set state to STATE_PLAYING to get higher priority. 552 setPlaybackState(PlaybackState.STATE_PLAYING); 553 554 // A media playback is also needed to receive media key events. 555 Utils.assertMediaPlaybackStarted(getContext()); 556 557 sessionCallback.reset(1); 558 simulateMediaKeyInput(KeyEvent.KEYCODE_MEDIA_PLAY); 559 assertTrue(sessionCallback.await(TIME_OUT_MS)); 560 assertEquals(1, sessionCallback.mOnPlayCalledCount); 561 assertTrue(compareRemoteUserInfo(mKeyDispatcherInfo, sessionCallback.mCallerInfo)); 562 563 sessionCallback.reset(1); 564 simulateMediaKeyInput(KeyEvent.KEYCODE_MEDIA_PAUSE); 565 assertTrue(sessionCallback.await(TIME_OUT_MS)); 566 assertTrue(sessionCallback.mOnPauseCalled); 567 assertTrue(compareRemoteUserInfo(mKeyDispatcherInfo, sessionCallback.mCallerInfo)); 568 569 sessionCallback.reset(1); 570 simulateMediaKeyInput(KeyEvent.KEYCODE_MEDIA_NEXT); 571 assertTrue(sessionCallback.await(TIME_OUT_MS)); 572 assertTrue(sessionCallback.mOnSkipToNextCalled); 573 assertTrue(compareRemoteUserInfo(mKeyDispatcherInfo, sessionCallback.mCallerInfo)); 574 575 sessionCallback.reset(1); 576 simulateMediaKeyInput(KeyEvent.KEYCODE_MEDIA_PREVIOUS); 577 assertTrue(sessionCallback.await(TIME_OUT_MS)); 578 assertTrue(sessionCallback.mOnSkipToPreviousCalled); 579 assertTrue(compareRemoteUserInfo(mKeyDispatcherInfo, sessionCallback.mCallerInfo)); 580 581 sessionCallback.reset(1); 582 simulateMediaKeyInput(KeyEvent.KEYCODE_MEDIA_STOP); 583 assertTrue(sessionCallback.await(TIME_OUT_MS)); 584 assertTrue(sessionCallback.mOnStopCalled); 585 assertTrue(compareRemoteUserInfo(mKeyDispatcherInfo, sessionCallback.mCallerInfo)); 586 587 sessionCallback.reset(1); 588 simulateMediaKeyInput(KeyEvent.KEYCODE_MEDIA_FAST_FORWARD); 589 assertTrue(sessionCallback.await(TIME_OUT_MS)); 590 assertTrue(sessionCallback.mOnFastForwardCalled); 591 assertTrue(compareRemoteUserInfo(mKeyDispatcherInfo, sessionCallback.mCallerInfo)); 592 593 sessionCallback.reset(1); 594 simulateMediaKeyInput(KeyEvent.KEYCODE_MEDIA_REWIND); 595 assertTrue(sessionCallback.await(TIME_OUT_MS)); 596 assertTrue(sessionCallback.mOnRewindCalled); 597 assertTrue(compareRemoteUserInfo(mKeyDispatcherInfo, sessionCallback.mCallerInfo)); 598 599 // Test PLAY_PAUSE button twice. 600 // First, simulate PLAY_PAUSE button while in STATE_PAUSED. 601 sessionCallback.reset(1); 602 setPlaybackState(PlaybackState.STATE_PAUSED); 603 simulateMediaKeyInput(KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE); 604 assertTrue(sessionCallback.await(TIME_OUT_MS)); 605 assertEquals(1, sessionCallback.mOnPlayCalledCount); 606 assertTrue(compareRemoteUserInfo(mKeyDispatcherInfo, sessionCallback.mCallerInfo)); 607 608 // Next, simulate PLAY_PAUSE button while in STATE_PLAYING. 609 sessionCallback.reset(1); 610 setPlaybackState(PlaybackState.STATE_PLAYING); 611 simulateMediaKeyInput(KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE); 612 assertTrue(sessionCallback.await(TIME_OUT_MS)); 613 assertTrue(sessionCallback.mOnPauseCalled); 614 assertTrue(compareRemoteUserInfo(mKeyDispatcherInfo, sessionCallback.mCallerInfo)); 615 616 // Double tap of PLAY_PAUSE is the next track instead of changing PLAY/PAUSE. 617 sessionCallback.reset(2); 618 setPlaybackState(PlaybackState.STATE_PLAYING); 619 simulateMediaKeyInput(KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE); 620 simulateMediaKeyInput(KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE); 621 assertFalse(sessionCallback.await(WAIT_MS)); 622 assertTrue(sessionCallback.mOnSkipToNextCalled); 623 assertEquals(0, sessionCallback.mOnPlayCalledCount); 624 assertFalse(sessionCallback.mOnPauseCalled); 625 assertTrue(compareRemoteUserInfo(mKeyDispatcherInfo, sessionCallback.mCallerInfo)); 626 627 // Test if PLAY_PAUSE double tap is considered as two single taps when another media 628 // key is pressed. 629 sessionCallback.reset(3); 630 setPlaybackState(PlaybackState.STATE_PAUSED); 631 simulateMediaKeyInput(KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE); 632 simulateMediaKeyInput(KeyEvent.KEYCODE_MEDIA_STOP); 633 simulateMediaKeyInput(KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE); 634 assertTrue(sessionCallback.await(TIME_OUT_MS)); 635 assertEquals(2, sessionCallback.mOnPlayCalledCount); 636 assertTrue(sessionCallback.mOnStopCalled); 637 assertTrue(compareRemoteUserInfo(mKeyDispatcherInfo, sessionCallback.mCallerInfo)); 638 639 // Test if media keys are handled in order. 640 sessionCallback.reset(2); 641 setPlaybackState(PlaybackState.STATE_PAUSED); 642 simulateMediaKeyInput(KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE); 643 simulateMediaKeyInput(KeyEvent.KEYCODE_MEDIA_STOP); 644 assertTrue(sessionCallback.await(TIME_OUT_MS)); 645 assertEquals(1, sessionCallback.mOnPlayCalledCount); 646 assertTrue(sessionCallback.mOnStopCalled); 647 assertTrue(compareRemoteUserInfo(mKeyDispatcherInfo, sessionCallback.mCallerInfo)); 648 synchronized (mWaitLock) { 649 assertEquals(PlaybackState.STATE_STOPPED, 650 mSession.getController().getPlaybackState().getState()); 651 } 652 } 653 654 /** 655 * Tests {@link MediaSession#setCallback} with {@code null}. No callbacks will be called 656 * once {@code setCallback(null)} is done. 657 */ testSetCallbackWithNull()658 public void testSetCallbackWithNull() throws Exception { 659 MediaSessionCallback sessionCallback = new MediaSessionCallback(); 660 mSession.setCallback(sessionCallback, mHandler); 661 mSession.setFlags(MediaSession.FLAG_HANDLES_TRANSPORT_CONTROLS); 662 mSession.setActive(true); 663 664 MediaController controller = mSession.getController(); 665 setPlaybackState(PlaybackState.STATE_PLAYING); 666 667 sessionCallback.reset(1); 668 mSession.setCallback(null, mHandler); 669 670 controller.getTransportControls().pause(); 671 assertFalse(sessionCallback.await(WAIT_MS)); 672 assertFalse("Callback shouldn't be called.", sessionCallback.mOnPauseCalled); 673 } 674 setPlaybackState(int state)675 private void setPlaybackState(int state) { 676 final long allActions = PlaybackState.ACTION_PLAY | PlaybackState.ACTION_PAUSE 677 | PlaybackState.ACTION_PLAY_PAUSE | PlaybackState.ACTION_STOP 678 | PlaybackState.ACTION_SKIP_TO_NEXT | PlaybackState.ACTION_SKIP_TO_PREVIOUS 679 | PlaybackState.ACTION_FAST_FORWARD | PlaybackState.ACTION_REWIND; 680 PlaybackState playbackState = new PlaybackState.Builder().setActions(allActions) 681 .setState(state, 0L, 0.0f).build(); 682 synchronized (mWaitLock) { 683 mSession.setPlaybackState(playbackState); 684 } 685 } 686 687 /** 688 * Test {@link MediaSession#release} doesn't crash when multiple media sessions are in the app 689 * which receives the media key events. 690 * See: b/36669550 691 */ testReleaseNoCrashWithMultipleSessions()692 public void testReleaseNoCrashWithMultipleSessions() throws Exception { 693 // Start a media playback for this app to receive media key events. 694 Utils.assertMediaPlaybackStarted(getContext()); 695 696 MediaSession anotherSession = null; 697 try { 698 anotherSession = new MediaSession(getContext(), TEST_SESSION_TAG); 699 mSession.release(); 700 anotherSession.release(); 701 702 // Try release with the different order. 703 mSession = new MediaSession(getContext(), TEST_SESSION_TAG); 704 anotherSession = new MediaSession(getContext(), TEST_SESSION_TAG); 705 anotherSession.release(); 706 mSession.release(); 707 } finally { 708 if (anotherSession != null) { 709 anotherSession.release(); 710 anotherSession = null; 711 } 712 } 713 } 714 715 // This uses public APIs to dispatch key events, so sessions would consider this as 716 // 'media key event from this application'. simulateMediaKeyInput(int keyCode)717 private void simulateMediaKeyInput(int keyCode) { 718 long downTime = System.currentTimeMillis(); 719 mAudioManager.dispatchMediaKeyEvent( 720 new KeyEvent(downTime, downTime, KeyEvent.ACTION_DOWN, keyCode, 0)); 721 mAudioManager.dispatchMediaKeyEvent( 722 new KeyEvent(downTime, System.currentTimeMillis(), KeyEvent.ACTION_UP, keyCode, 0)); 723 } 724 725 /** 726 * Tests {@link MediaSession.QueueItem}. 727 */ testQueueItem()728 public void testQueueItem() { 729 MediaDescription.Builder descriptionBuilder = new MediaDescription.Builder() 730 .setMediaId("media-id") 731 .setTitle("title"); 732 733 try { 734 new QueueItem(/*description=*/null, TEST_QUEUE_ID); 735 fail(); 736 } catch (IllegalArgumentException e) { 737 // Expected 738 } 739 try { 740 new QueueItem(descriptionBuilder.build(), QueueItem.UNKNOWN_ID); 741 fail(); 742 } catch (IllegalArgumentException e) { 743 // Expected 744 } 745 746 QueueItem item = new QueueItem(descriptionBuilder.build(), TEST_QUEUE_ID); 747 748 Parcel p = Parcel.obtain(); 749 item.writeToParcel(p, 0); 750 p.setDataPosition(0); 751 QueueItem other = QueueItem.CREATOR.createFromParcel(p); 752 assertEquals(item.toString(), other.toString()); 753 p.recycle(); 754 755 final int arraySize = 5; 756 QueueItem[] queueItemArray = QueueItem.CREATOR.newArray(arraySize); 757 assertNotNull(queueItemArray); 758 assertEquals(arraySize, queueItemArray.length); 759 for (QueueItem elem : queueItemArray) { 760 assertNull(elem); 761 } 762 } 763 testQueueItemEquals()764 public void testQueueItemEquals() { 765 MediaDescription.Builder descriptionBuilder = new MediaDescription.Builder() 766 .setMediaId("media-id") 767 .setTitle("title"); 768 769 QueueItem item = new QueueItem(descriptionBuilder.build(), TEST_QUEUE_ID); 770 assertEquals(TEST_QUEUE_ID, item.getQueueId()); 771 assertEquals("media-id", item.getDescription().getMediaId()); 772 assertEquals("title", item.getDescription().getTitle()); 773 assertEquals(0, item.describeContents()); 774 775 assertFalse(item.equals(null)); 776 assertFalse(item.equals(descriptionBuilder.build())); 777 778 QueueItem sameItem = new QueueItem(descriptionBuilder.build(), TEST_QUEUE_ID); 779 assertTrue(item.equals(sameItem)); 780 781 QueueItem differentQueueId = new QueueItem( 782 descriptionBuilder.build(), TEST_QUEUE_ID + 1); 783 assertFalse(item.equals(differentQueueId)); 784 785 QueueItem differentDescription = new QueueItem( 786 descriptionBuilder.setTitle("title2").build(), TEST_QUEUE_ID); 787 assertFalse(item.equals(differentDescription)); 788 } 789 testSessionInfoWithFrameworkParcelable()790 public void testSessionInfoWithFrameworkParcelable() { 791 final String testKey = "test_key"; 792 final AudioAttributes frameworkParcelable = new AudioAttributes.Builder().build(); 793 794 Bundle sessionInfo = new Bundle(); 795 sessionInfo.putParcelable(testKey, frameworkParcelable); 796 797 MediaSession session = null; 798 try { 799 session = new MediaSession( 800 mContext, "testSessionInfoWithFrameworkParcelable", sessionInfo); 801 Bundle sessionInfoOut = session.getController().getSessionInfo(); 802 assertTrue(sessionInfoOut.containsKey(testKey)); 803 assertEquals(frameworkParcelable, sessionInfoOut.getParcelable(testKey)); 804 } finally { 805 if (session != null) { 806 session.release(); 807 } 808 } 809 810 } 811 testSessionInfoWithCustomParcelable()812 public void testSessionInfoWithCustomParcelable() { 813 final String testKey = "test_key"; 814 final MediaSession2Test.CustomParcelable customParcelable = 815 new MediaSession2Test.CustomParcelable(1); 816 817 Bundle sessionInfo = new Bundle(); 818 sessionInfo.putParcelable(testKey, customParcelable); 819 820 MediaSession session = null; 821 try { 822 session = new MediaSession( 823 mContext, "testSessionInfoWithCustomParcelable", sessionInfo); 824 fail("Custom Parcelable shouldn't be accepted!"); 825 } catch (IllegalArgumentException e) { 826 // Expected 827 } finally { 828 if (session != null) { 829 session.release(); 830 } 831 } 832 } 833 834 /** 835 * An app should not be able to create too many sessions. 836 * See MediaSessionService#SESSION_CREATION_LIMIT_PER_UID 837 */ testSessionCreationLimit()838 public void testSessionCreationLimit() { 839 List<MediaSession> sessions = new ArrayList<>(); 840 try { 841 for (int i = 0; i < TEST_TOO_MANY_SESSION_COUNT; i++) { 842 sessions.add(new MediaSession(mContext, "testSessionCreationLimit")); 843 } 844 fail("The number of session should be limited!"); 845 } catch (RuntimeException e) { 846 // Expected 847 } finally { 848 for (MediaSession session : sessions) { 849 session.release(); 850 } 851 } 852 } 853 854 /** 855 * Check that calling {@link MediaSession#release()} multiple times for the same session 856 * does not decrement current session count multiple times. 857 */ testSessionCreationLimitWithMediaSessionRelease()858 public void testSessionCreationLimitWithMediaSessionRelease() { 859 List<MediaSession> sessions = new ArrayList<>(); 860 MediaSession sessionToReleaseMultipleTimes = null; 861 try { 862 sessionToReleaseMultipleTimes = new MediaSession( 863 mContext, "testSessionCreationLimitWithMediaSessionRelease"); 864 for (int i = 0; i < TEST_TOO_MANY_SESSION_COUNT; i++) { 865 sessions.add(new MediaSession( 866 mContext, "testSessionCreationLimitWithMediaSessionRelease")); 867 // Call release() many times with the same session. 868 sessionToReleaseMultipleTimes.release(); 869 } 870 fail("The number of session should be limited!"); 871 } catch (RuntimeException e) { 872 // Expected 873 } finally { 874 for (MediaSession session : sessions) { 875 session.release(); 876 } 877 if (sessionToReleaseMultipleTimes != null) { 878 sessionToReleaseMultipleTimes.release(); 879 } 880 } 881 } 882 883 /** 884 * Check that calling {@link MediaSession2#close()} does not decrement current session count. 885 */ testSessionCreationLimitWithMediaSession2Release()886 public void testSessionCreationLimitWithMediaSession2Release() { 887 List<MediaSession> sessions = new ArrayList<>(); 888 try { 889 for (int i = 0; i < 1000; i++) { 890 sessions.add(new MediaSession( 891 mContext, "testSessionCreationLimitWithMediaSession2Release")); 892 893 try (MediaSession2 session2 = new MediaSession2.Builder(mContext).build()) { 894 // Do nothing 895 } 896 } 897 fail("The number of session should be limited!"); 898 } catch (RuntimeException e) { 899 // Expected 900 } finally { 901 for (MediaSession session : sessions) { 902 session.release(); 903 } 904 } 905 } 906 907 /** 908 * Check that a series of {@link MediaSession#setQueue} does not break {@link MediaController} 909 * on the remote process due to binder buffer overflow. 910 */ testSeriesOfSetQueue()911 public void testSeriesOfSetQueue() throws Exception { 912 int numberOfCalls = 100; 913 int queueSize = 1_000; 914 List<QueueItem> queue = new ArrayList<>(); 915 for (int id = 0; id < queueSize; id++) { 916 MediaDescription description = new MediaDescription.Builder() 917 .setMediaId(Integer.toString(id)).build(); 918 queue.add(new QueueItem(description, id)); 919 } 920 921 try (RemoteService.Invoker invoker = new RemoteService.Invoker(mContext, 922 MediaSessionTestService.class, TEST_SERIES_OF_SET_QUEUE)) { 923 Bundle args = new Bundle(); 924 args.putParcelable(KEY_SESSION_TOKEN, mSession.getSessionToken()); 925 args.putInt(KEY_EXPECTED_TOTAL_NUMBER_OF_ITEMS, numberOfCalls * queueSize); 926 invoker.run(STEP_SET_UP, args); 927 for (int i = 0; i < numberOfCalls; i++) { 928 mSession.setQueue(queue); 929 } 930 invoker.run(STEP_CHECK); 931 invoker.run(STEP_CLEAN_UP); 932 } 933 } 934 testSetQueueWithLargeNumberOfItems()935 public void testSetQueueWithLargeNumberOfItems() throws Exception { 936 int queueSize = 1_000_000; 937 List<QueueItem> queue = new ArrayList<>(); 938 for (int id = 0; id < queueSize; id++) { 939 MediaDescription description = new MediaDescription.Builder() 940 .setMediaId(Integer.toString(id)).build(); 941 queue.add(new QueueItem(description, id)); 942 } 943 944 try (RemoteService.Invoker invoker = new RemoteService.Invoker(mContext, 945 MediaSessionTestService.class, TEST_SET_QUEUE)) { 946 Bundle args = new Bundle(); 947 args.putParcelable(KEY_SESSION_TOKEN, mSession.getSessionToken()); 948 args.putInt(KEY_EXPECTED_QUEUE_SIZE, queueSize); 949 invoker.run(STEP_SET_UP, args); 950 mSession.setQueue(queue); 951 invoker.run(STEP_CHECK); 952 invoker.run(STEP_CLEAN_UP); 953 } 954 } 955 testSetQueueWithEmptyQueue()956 public void testSetQueueWithEmptyQueue() throws Exception { 957 try (RemoteService.Invoker invoker = new RemoteService.Invoker(mContext, 958 MediaSessionTestService.class, TEST_SET_QUEUE)) { 959 Bundle args = new Bundle(); 960 args.putParcelable(KEY_SESSION_TOKEN, mSession.getSessionToken()); 961 args.putInt(KEY_EXPECTED_QUEUE_SIZE, 0); 962 invoker.run(STEP_SET_UP, args); 963 mSession.setQueue(Collections.emptyList()); 964 invoker.run(STEP_CHECK); 965 invoker.run(STEP_CLEAN_UP); 966 } 967 } 968 969 /** 970 * Verifies that a new session hasn't had any configuration bits set yet. 971 * 972 * @param controller The controller for the session 973 */ verifyNewSession(MediaController controller)974 private void verifyNewSession(MediaController controller) { 975 assertEquals("New session has unexpected configuration", 0L, controller.getFlags()); 976 assertNull("New session has unexpected configuration", controller.getExtras()); 977 assertNull("New session has unexpected configuration", controller.getMetadata()); 978 assertEquals("New session has unexpected configuration", 979 getContext().getPackageName(), controller.getPackageName()); 980 assertNull("New session has unexpected configuration", controller.getPlaybackState()); 981 assertNull("New session has unexpected configuration", controller.getQueue()); 982 assertNull("New session has unexpected configuration", controller.getQueueTitle()); 983 assertEquals("New session has unexpected configuration", Rating.RATING_NONE, 984 controller.getRatingType()); 985 assertNull("New session has unexpected configuration", controller.getSessionActivity()); 986 987 assertNotNull(controller.getSessionToken()); 988 assertNotNull(controller.getTransportControls()); 989 990 MediaController.PlaybackInfo info = controller.getPlaybackInfo(); 991 assertNotNull(info); 992 info.toString(); // Test that calling PlaybackInfo.toString() does not crash. 993 assertEquals(MediaController.PlaybackInfo.PLAYBACK_TYPE_LOCAL, info.getPlaybackType()); 994 AudioAttributes attrs = info.getAudioAttributes(); 995 assertNotNull(attrs); 996 assertEquals(AudioAttributes.USAGE_MEDIA, attrs.getUsage()); 997 assertEquals(mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC), 998 info.getCurrentVolume()); 999 } 1000 1001 private class MediaControllerCallback extends MediaController.Callback { 1002 private volatile boolean mOnPlaybackStateChangedCalled; 1003 private volatile boolean mOnMetadataChangedCalled; 1004 private volatile boolean mOnQueueChangedCalled; 1005 private volatile boolean mOnQueueTitleChangedCalled; 1006 private volatile boolean mOnExtraChangedCalled; 1007 private volatile boolean mOnAudioInfoChangedCalled; 1008 private volatile boolean mOnSessionDestroyedCalled; 1009 private volatile boolean mOnSessionEventCalled; 1010 1011 private volatile PlaybackState mPlaybackState; 1012 private volatile MediaMetadata mMediaMetadata; 1013 private volatile List<QueueItem> mQueue; 1014 private volatile CharSequence mTitle; 1015 private volatile String mEvent; 1016 private volatile Bundle mExtras; 1017 private volatile MediaController.PlaybackInfo mPlaybackInfo; 1018 resetLocked()1019 public void resetLocked() { 1020 mOnPlaybackStateChangedCalled = false; 1021 mOnMetadataChangedCalled = false; 1022 mOnQueueChangedCalled = false; 1023 mOnQueueTitleChangedCalled = false; 1024 mOnExtraChangedCalled = false; 1025 mOnAudioInfoChangedCalled = false; 1026 mOnSessionDestroyedCalled = false; 1027 mOnSessionEventCalled = false; 1028 1029 mPlaybackState = null; 1030 mMediaMetadata = null; 1031 mQueue = null; 1032 mTitle = null; 1033 mExtras = null; 1034 mPlaybackInfo = null; 1035 } 1036 1037 @Override onPlaybackStateChanged(PlaybackState state)1038 public void onPlaybackStateChanged(PlaybackState state) { 1039 synchronized (mWaitLock) { 1040 mOnPlaybackStateChangedCalled = true; 1041 mPlaybackState = state; 1042 mWaitLock.notify(); 1043 } 1044 } 1045 1046 @Override onMetadataChanged(MediaMetadata metadata)1047 public void onMetadataChanged(MediaMetadata metadata) { 1048 synchronized (mWaitLock) { 1049 mOnMetadataChangedCalled = true; 1050 mMediaMetadata = metadata; 1051 mWaitLock.notify(); 1052 } 1053 } 1054 1055 @Override onQueueChanged(List<QueueItem> queue)1056 public void onQueueChanged(List<QueueItem> queue) { 1057 synchronized (mWaitLock) { 1058 mOnQueueChangedCalled = true; 1059 mQueue = queue; 1060 mWaitLock.notify(); 1061 } 1062 } 1063 1064 @Override onQueueTitleChanged(CharSequence title)1065 public void onQueueTitleChanged(CharSequence title) { 1066 synchronized (mWaitLock) { 1067 mOnQueueTitleChangedCalled = true; 1068 mTitle = title; 1069 mWaitLock.notify(); 1070 } 1071 } 1072 1073 @Override onExtrasChanged(Bundle extras)1074 public void onExtrasChanged(Bundle extras) { 1075 synchronized (mWaitLock) { 1076 mOnExtraChangedCalled = true; 1077 mExtras = extras; 1078 mWaitLock.notify(); 1079 } 1080 } 1081 1082 @Override onAudioInfoChanged(MediaController.PlaybackInfo info)1083 public void onAudioInfoChanged(MediaController.PlaybackInfo info) { 1084 synchronized (mWaitLock) { 1085 mOnAudioInfoChangedCalled = true; 1086 mPlaybackInfo = info; 1087 mWaitLock.notify(); 1088 } 1089 } 1090 1091 @Override onSessionDestroyed()1092 public void onSessionDestroyed() { 1093 synchronized (mWaitLock) { 1094 mOnSessionDestroyedCalled = true; 1095 mWaitLock.notify(); 1096 } 1097 } 1098 1099 @Override onSessionEvent(String event, Bundle extras)1100 public void onSessionEvent(String event, Bundle extras) { 1101 synchronized (mWaitLock) { 1102 mOnSessionEventCalled = true; 1103 mEvent = event; 1104 mExtras = (Bundle) extras.clone(); 1105 mWaitLock.notify(); 1106 } 1107 } 1108 } 1109 1110 private class MediaSessionCallback extends MediaSession.Callback { 1111 private CountDownLatch mLatch; 1112 private int mOnPlayCalledCount; 1113 private boolean mOnPauseCalled; 1114 private boolean mOnStopCalled; 1115 private boolean mOnFastForwardCalled; 1116 private boolean mOnRewindCalled; 1117 private boolean mOnSkipToPreviousCalled; 1118 private boolean mOnSkipToNextCalled; 1119 private RemoteUserInfo mCallerInfo; 1120 reset(int count)1121 public void reset(int count) { 1122 mLatch = new CountDownLatch(count); 1123 mOnPlayCalledCount = 0; 1124 mOnPauseCalled = false; 1125 mOnStopCalled = false; 1126 mOnFastForwardCalled = false; 1127 mOnRewindCalled = false; 1128 mOnSkipToPreviousCalled = false; 1129 mOnSkipToNextCalled = false; 1130 } 1131 await(long waitMs)1132 public boolean await(long waitMs) { 1133 try { 1134 return mLatch.await(waitMs, TimeUnit.MILLISECONDS); 1135 } catch (InterruptedException e) { 1136 return false; 1137 } 1138 } 1139 1140 @Override onPlay()1141 public void onPlay() { 1142 mOnPlayCalledCount++; 1143 mCallerInfo = mSession.getCurrentControllerInfo(); 1144 setPlaybackState(PlaybackState.STATE_PLAYING); 1145 mLatch.countDown(); 1146 } 1147 1148 @Override onPause()1149 public void onPause() { 1150 mOnPauseCalled = true; 1151 mCallerInfo = mSession.getCurrentControllerInfo(); 1152 setPlaybackState(PlaybackState.STATE_PAUSED); 1153 mLatch.countDown(); 1154 } 1155 1156 @Override onStop()1157 public void onStop() { 1158 mOnStopCalled = true; 1159 mCallerInfo = mSession.getCurrentControllerInfo(); 1160 setPlaybackState(PlaybackState.STATE_STOPPED); 1161 mLatch.countDown(); 1162 } 1163 1164 @Override onFastForward()1165 public void onFastForward() { 1166 mOnFastForwardCalled = true; 1167 mCallerInfo = mSession.getCurrentControllerInfo(); 1168 mLatch.countDown(); 1169 } 1170 1171 @Override onRewind()1172 public void onRewind() { 1173 mOnRewindCalled = true; 1174 mCallerInfo = mSession.getCurrentControllerInfo(); 1175 mLatch.countDown(); 1176 } 1177 1178 @Override onSkipToPrevious()1179 public void onSkipToPrevious() { 1180 mOnSkipToPreviousCalled = true; 1181 mCallerInfo = mSession.getCurrentControllerInfo(); 1182 mLatch.countDown(); 1183 } 1184 1185 @Override onSkipToNext()1186 public void onSkipToNext() { 1187 mOnSkipToNextCalled = true; 1188 mCallerInfo = mSession.getCurrentControllerInfo(); 1189 mLatch.countDown(); 1190 } 1191 } 1192 } 1193