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.Utils.compareRemoteUserInfo; 20 21 import static org.junit.Assert.fail; 22 23 import android.app.PendingIntent; 24 import android.content.ComponentName; 25 import android.content.Context; 26 import android.content.Intent; 27 import android.media.AudioAttributes; 28 import android.media.AudioManager; 29 import android.media.MediaDescription; 30 import android.media.MediaMetadata; 31 import android.media.MediaSession2; 32 import android.media.Rating; 33 import android.media.VolumeProvider; 34 import android.media.session.MediaController; 35 import android.media.session.MediaSession; 36 import android.media.session.MediaSession.QueueItem; 37 import android.media.session.MediaSessionManager; 38 import android.media.session.MediaSessionManager.RemoteUserInfo; 39 import android.media.session.PlaybackState; 40 import android.os.Bundle; 41 import android.os.Handler; 42 import android.os.Looper; 43 import android.os.Parcel; 44 import android.os.Process; 45 import android.platform.test.annotations.AppModeFull; 46 import android.test.AndroidTestCase; 47 import android.view.KeyEvent; 48 49 import java.util.ArrayList; 50 import java.util.List; 51 import java.util.concurrent.CountDownLatch; 52 import java.util.concurrent.TimeUnit; 53 54 @AppModeFull(reason = "TODO: evaluate and port to instant") 55 public class MediaSessionTest extends AndroidTestCase { 56 // The maximum time to wait for an operation that is expected to succeed. 57 private static final long TIME_OUT_MS = 3000L; 58 // The maximum time to wait for an operation that is expected to fail. 59 private static final long WAIT_MS = 100L; 60 private static final int MAX_AUDIO_INFO_CHANGED_CALLBACK_COUNT = 10; 61 private static final String TEST_SESSION_TAG = "test-session-tag"; 62 private static final String TEST_KEY = "test-key"; 63 private static final String TEST_VALUE = "test-val"; 64 private static final String TEST_SESSION_EVENT = "test-session-event"; 65 private static final int TEST_CURRENT_VOLUME = 10; 66 private static final int TEST_MAX_VOLUME = 11; 67 private static final long TEST_QUEUE_ID = 12L; 68 private static final long TEST_ACTION = 55L; 69 70 private AudioManager mAudioManager; 71 private Handler mHandler = new Handler(Looper.getMainLooper()); 72 private Object mWaitLock = new Object(); 73 private MediaControllerCallback mCallback = new MediaControllerCallback(); 74 private MediaSession mSession; 75 private RemoteUserInfo mKeyDispatcherInfo; 76 77 @Override setUp()78 protected void setUp() throws Exception { 79 super.setUp(); 80 mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE); 81 mSession = new MediaSession(getContext(), TEST_SESSION_TAG); 82 mKeyDispatcherInfo = new MediaSessionManager.RemoteUserInfo( 83 getContext().getPackageName(), Process.myPid(), Process.myUid()); 84 } 85 86 @Override tearDown()87 protected void tearDown() throws Exception { 88 // It is OK to call release() twice. 89 mSession.release(); 90 super.tearDown(); 91 } 92 93 /** 94 * Tests that a session can be created and that all the fields are 95 * initialized correctly. 96 */ testCreateSession()97 public void testCreateSession() throws Exception { 98 assertNotNull(mSession.getSessionToken()); 99 assertFalse("New session should not be active", mSession.isActive()); 100 101 // Verify by getting the controller and checking all its fields 102 MediaController controller = mSession.getController(); 103 assertNotNull(controller); 104 verifyNewSession(controller); 105 } 106 107 /** 108 * Tests MediaSession.Token created in the constructor of MediaSession. 109 */ testSessionToken()110 public void testSessionToken() throws Exception { 111 MediaSession.Token sessionToken = mSession.getSessionToken(); 112 113 assertNotNull(sessionToken); 114 assertEquals(0, sessionToken.describeContents()); 115 116 // Test writeToParcel 117 Parcel p = Parcel.obtain(); 118 sessionToken.writeToParcel(p, 0); 119 p.setDataPosition(0); 120 MediaSession.Token token = MediaSession.Token.CREATOR.createFromParcel(p); 121 assertEquals(token, sessionToken); 122 p.recycle(); 123 } 124 125 /** 126 * Tests that the various configuration bits on a session get passed to the 127 * controller. 128 */ testConfigureSession()129 public void testConfigureSession() throws Exception { 130 MediaController controller = mSession.getController(); 131 controller.registerCallback(mCallback, mHandler); 132 final MediaController.Callback callback = (MediaController.Callback) mCallback; 133 134 synchronized (mWaitLock) { 135 // test setExtras 136 mCallback.resetLocked(); 137 final Bundle extras = new Bundle(); 138 extras.putString(TEST_KEY, TEST_VALUE); 139 mSession.setExtras(extras); 140 mWaitLock.wait(TIME_OUT_MS); 141 assertTrue(mCallback.mOnExtraChangedCalled); 142 // just call the callback once directly so it's marked as tested 143 callback.onExtrasChanged(mCallback.mExtras); 144 145 Bundle extrasOut = mCallback.mExtras; 146 assertNotNull(extrasOut); 147 assertEquals(TEST_VALUE, extrasOut.get(TEST_KEY)); 148 149 extrasOut = controller.getExtras(); 150 assertNotNull(extrasOut); 151 assertEquals(TEST_VALUE, extrasOut.get(TEST_KEY)); 152 153 // test setFlags 154 mSession.setFlags(5); 155 assertEquals(5, controller.getFlags()); 156 157 // test setMetadata 158 mCallback.resetLocked(); 159 MediaMetadata metadata = 160 new MediaMetadata.Builder().putString(TEST_KEY, TEST_VALUE).build(); 161 mSession.setMetadata(metadata); 162 mWaitLock.wait(TIME_OUT_MS); 163 assertTrue(mCallback.mOnMetadataChangedCalled); 164 // just call the callback once directly so it's marked as tested 165 callback.onMetadataChanged(mCallback.mMediaMetadata); 166 167 MediaMetadata metadataOut = mCallback.mMediaMetadata; 168 assertNotNull(metadataOut); 169 assertEquals(TEST_VALUE, metadataOut.getString(TEST_KEY)); 170 171 metadataOut = controller.getMetadata(); 172 assertNotNull(metadataOut); 173 assertEquals(TEST_VALUE, metadataOut.getString(TEST_KEY)); 174 175 // test setPlaybackState 176 mCallback.resetLocked(); 177 PlaybackState state = new PlaybackState.Builder().setActions(TEST_ACTION).build(); 178 mSession.setPlaybackState(state); 179 mWaitLock.wait(TIME_OUT_MS); 180 assertTrue(mCallback.mOnPlaybackStateChangedCalled); 181 // just call the callback once directly so it's marked as tested 182 callback.onPlaybackStateChanged(mCallback.mPlaybackState); 183 184 PlaybackState stateOut = mCallback.mPlaybackState; 185 assertNotNull(stateOut); 186 assertEquals(TEST_ACTION, stateOut.getActions()); 187 188 stateOut = controller.getPlaybackState(); 189 assertNotNull(stateOut); 190 assertEquals(TEST_ACTION, stateOut.getActions()); 191 192 // test setQueue and setQueueTitle 193 mCallback.resetLocked(); 194 List<QueueItem> queue = new ArrayList<>(); 195 QueueItem item = new QueueItem(new MediaDescription.Builder() 196 .setMediaId(TEST_VALUE).setTitle("title").build(), TEST_QUEUE_ID); 197 queue.add(item); 198 mSession.setQueue(queue); 199 mWaitLock.wait(TIME_OUT_MS); 200 assertTrue(mCallback.mOnQueueChangedCalled); 201 // just call the callback once directly so it's marked as tested 202 callback.onQueueChanged(mCallback.mQueue); 203 204 mSession.setQueueTitle(TEST_VALUE); 205 mWaitLock.wait(TIME_OUT_MS); 206 assertTrue(mCallback.mOnQueueTitleChangedCalled); 207 208 assertEquals(TEST_VALUE, mCallback.mTitle); 209 assertEquals(queue.size(), mCallback.mQueue.size()); 210 assertEquals(TEST_QUEUE_ID, mCallback.mQueue.get(0).getQueueId()); 211 assertEquals(TEST_VALUE, mCallback.mQueue.get(0).getDescription().getMediaId()); 212 213 assertEquals(TEST_VALUE, controller.getQueueTitle()); 214 assertEquals(queue.size(), controller.getQueue().size()); 215 assertEquals(TEST_QUEUE_ID, controller.getQueue().get(0).getQueueId()); 216 assertEquals(TEST_VALUE, controller.getQueue().get(0).getDescription().getMediaId()); 217 218 mCallback.resetLocked(); 219 mSession.setQueue(null); 220 mWaitLock.wait(TIME_OUT_MS); 221 assertTrue(mCallback.mOnQueueChangedCalled); 222 // just call the callback once directly so it's marked as tested 223 callback.onQueueChanged(mCallback.mQueue); 224 225 mSession.setQueueTitle(null); 226 mWaitLock.wait(TIME_OUT_MS); 227 assertTrue(mCallback.mOnQueueTitleChangedCalled); 228 // just call the callback once directly so it's marked as tested 229 callback.onQueueTitleChanged(mCallback.mTitle); 230 231 assertNull(mCallback.mTitle); 232 assertNull(mCallback.mQueue); 233 assertNull(controller.getQueueTitle()); 234 assertNull(controller.getQueue()); 235 236 // test setSessionActivity 237 Intent intent = new Intent("cts.MEDIA_SESSION_ACTION"); 238 PendingIntent pi = PendingIntent.getActivity(getContext(), 555, intent, 0); 239 mSession.setSessionActivity(pi); 240 assertEquals(pi, controller.getSessionActivity()); 241 242 // test setActivity 243 mSession.setActive(true); 244 assertTrue(mSession.isActive()); 245 246 // test sendSessionEvent 247 mCallback.resetLocked(); 248 mSession.sendSessionEvent(TEST_SESSION_EVENT, extras); 249 mWaitLock.wait(TIME_OUT_MS); 250 251 assertTrue(mCallback.mOnSessionEventCalled); 252 assertEquals(TEST_SESSION_EVENT, mCallback.mEvent); 253 assertEquals(TEST_VALUE, mCallback.mExtras.getString(TEST_KEY)); 254 // just call the callback once directly so it's marked as tested 255 callback.onSessionEvent(mCallback.mEvent, mCallback.mExtras); 256 257 // test release 258 mCallback.resetLocked(); 259 mSession.release(); 260 mWaitLock.wait(TIME_OUT_MS); 261 assertTrue(mCallback.mOnSessionDestroyedCalled); 262 // just call the callback once directly so it's marked as tested 263 callback.onSessionDestroyed(); 264 } 265 } 266 267 /** 268 * Test {@link MediaSession#setPlaybackToLocal} and {@link MediaSession#setPlaybackToRemote}. 269 */ testPlaybackToLocalAndRemote()270 public void testPlaybackToLocalAndRemote() throws Exception { 271 MediaController controller = mSession.getController(); 272 controller.registerCallback(mCallback, mHandler); 273 274 synchronized (mWaitLock) { 275 // test setPlaybackToRemote, do this before testing setPlaybackToLocal 276 // to ensure it switches correctly. 277 mCallback.resetLocked(); 278 try { 279 mSession.setPlaybackToRemote(null); 280 fail("Expected IAE for setPlaybackToRemote(null)"); 281 } catch (IllegalArgumentException e) { 282 // expected 283 } 284 VolumeProvider vp = new VolumeProvider(VolumeProvider.VOLUME_CONTROL_FIXED, 285 TEST_MAX_VOLUME, TEST_CURRENT_VOLUME) {}; 286 mSession.setPlaybackToRemote(vp); 287 288 MediaController.PlaybackInfo info = null; 289 for (int i = 0; i < MAX_AUDIO_INFO_CHANGED_CALLBACK_COUNT; ++i) { 290 mCallback.mOnAudioInfoChangedCalled = false; 291 mWaitLock.wait(TIME_OUT_MS); 292 assertTrue(mCallback.mOnAudioInfoChangedCalled); 293 info = mCallback.mPlaybackInfo; 294 if (info != null && info.getCurrentVolume() == TEST_CURRENT_VOLUME 295 && info.getMaxVolume() == TEST_MAX_VOLUME 296 && info.getVolumeControl() == VolumeProvider.VOLUME_CONTROL_FIXED 297 && info.getPlaybackType() 298 == MediaController.PlaybackInfo.PLAYBACK_TYPE_REMOTE) { 299 break; 300 } 301 } 302 assertNotNull(info); 303 assertEquals(MediaController.PlaybackInfo.PLAYBACK_TYPE_REMOTE, info.getPlaybackType()); 304 assertEquals(TEST_MAX_VOLUME, info.getMaxVolume()); 305 assertEquals(TEST_CURRENT_VOLUME, info.getCurrentVolume()); 306 assertEquals(VolumeProvider.VOLUME_CONTROL_FIXED, info.getVolumeControl()); 307 308 info = controller.getPlaybackInfo(); 309 assertNotNull(info); 310 assertEquals(MediaController.PlaybackInfo.PLAYBACK_TYPE_REMOTE, info.getPlaybackType()); 311 assertEquals(TEST_MAX_VOLUME, info.getMaxVolume()); 312 assertEquals(TEST_CURRENT_VOLUME, info.getCurrentVolume()); 313 assertEquals(VolumeProvider.VOLUME_CONTROL_FIXED, info.getVolumeControl()); 314 315 // test setPlaybackToLocal 316 AudioAttributes attrs = new AudioAttributes.Builder().setUsage(USAGE_GAME).build(); 317 mSession.setPlaybackToLocal(attrs); 318 319 info = controller.getPlaybackInfo(); 320 assertNotNull(info); 321 assertEquals(MediaController.PlaybackInfo.PLAYBACK_TYPE_LOCAL, info.getPlaybackType()); 322 assertEquals(attrs, info.getAudioAttributes()); 323 } 324 } 325 326 /** 327 * Test {@link MediaSession.Callback#onMediaButtonEvent}. 328 */ testCallbackOnMediaButtonEvent()329 public void testCallbackOnMediaButtonEvent() throws Exception { 330 MediaSessionCallback sessionCallback = new MediaSessionCallback(); 331 mSession.setCallback(sessionCallback, new Handler(Looper.getMainLooper())); 332 mSession.setFlags(MediaSession.FLAG_HANDLES_MEDIA_BUTTONS); 333 mSession.setActive(true); 334 335 Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON).setComponent( 336 new ComponentName(getContext(), getContext().getClass())); 337 PendingIntent pi = PendingIntent.getBroadcast(getContext(), 0, mediaButtonIntent, 0); 338 mSession.setMediaButtonReceiver(pi); 339 340 // Set state to STATE_PLAYING to get higher priority. 341 setPlaybackState(PlaybackState.STATE_PLAYING); 342 343 // A media playback is also needed to receive media key events. 344 Utils.assertMediaPlaybackStarted(getContext()); 345 346 sessionCallback.reset(1); 347 simulateMediaKeyInput(KeyEvent.KEYCODE_MEDIA_PLAY); 348 assertTrue(sessionCallback.await(TIME_OUT_MS)); 349 assertEquals(1, sessionCallback.mOnPlayCalledCount); 350 assertTrue(compareRemoteUserInfo(mKeyDispatcherInfo, sessionCallback.mCallerInfo)); 351 352 sessionCallback.reset(1); 353 simulateMediaKeyInput(KeyEvent.KEYCODE_MEDIA_PAUSE); 354 assertTrue(sessionCallback.await(TIME_OUT_MS)); 355 assertTrue(sessionCallback.mOnPauseCalled); 356 assertTrue(compareRemoteUserInfo(mKeyDispatcherInfo, sessionCallback.mCallerInfo)); 357 358 sessionCallback.reset(1); 359 simulateMediaKeyInput(KeyEvent.KEYCODE_MEDIA_NEXT); 360 assertTrue(sessionCallback.await(TIME_OUT_MS)); 361 assertTrue(sessionCallback.mOnSkipToNextCalled); 362 assertTrue(compareRemoteUserInfo(mKeyDispatcherInfo, sessionCallback.mCallerInfo)); 363 364 sessionCallback.reset(1); 365 simulateMediaKeyInput(KeyEvent.KEYCODE_MEDIA_PREVIOUS); 366 assertTrue(sessionCallback.await(TIME_OUT_MS)); 367 assertTrue(sessionCallback.mOnSkipToPreviousCalled); 368 assertTrue(compareRemoteUserInfo(mKeyDispatcherInfo, sessionCallback.mCallerInfo)); 369 370 sessionCallback.reset(1); 371 simulateMediaKeyInput(KeyEvent.KEYCODE_MEDIA_STOP); 372 assertTrue(sessionCallback.await(TIME_OUT_MS)); 373 assertTrue(sessionCallback.mOnStopCalled); 374 assertTrue(compareRemoteUserInfo(mKeyDispatcherInfo, sessionCallback.mCallerInfo)); 375 376 sessionCallback.reset(1); 377 simulateMediaKeyInput(KeyEvent.KEYCODE_MEDIA_FAST_FORWARD); 378 assertTrue(sessionCallback.await(TIME_OUT_MS)); 379 assertTrue(sessionCallback.mOnFastForwardCalled); 380 assertTrue(compareRemoteUserInfo(mKeyDispatcherInfo, sessionCallback.mCallerInfo)); 381 382 sessionCallback.reset(1); 383 simulateMediaKeyInput(KeyEvent.KEYCODE_MEDIA_REWIND); 384 assertTrue(sessionCallback.await(TIME_OUT_MS)); 385 assertTrue(sessionCallback.mOnRewindCalled); 386 assertTrue(compareRemoteUserInfo(mKeyDispatcherInfo, sessionCallback.mCallerInfo)); 387 388 // Test PLAY_PAUSE button twice. 389 // First, simulate PLAY_PAUSE button while in STATE_PAUSED. 390 sessionCallback.reset(1); 391 setPlaybackState(PlaybackState.STATE_PAUSED); 392 simulateMediaKeyInput(KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE); 393 assertTrue(sessionCallback.await(TIME_OUT_MS)); 394 assertEquals(1, sessionCallback.mOnPlayCalledCount); 395 assertTrue(compareRemoteUserInfo(mKeyDispatcherInfo, sessionCallback.mCallerInfo)); 396 397 // Next, simulate PLAY_PAUSE button while in STATE_PLAYING. 398 sessionCallback.reset(1); 399 setPlaybackState(PlaybackState.STATE_PLAYING); 400 simulateMediaKeyInput(KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE); 401 assertTrue(sessionCallback.await(TIME_OUT_MS)); 402 assertTrue(sessionCallback.mOnPauseCalled); 403 assertTrue(compareRemoteUserInfo(mKeyDispatcherInfo, sessionCallback.mCallerInfo)); 404 405 // Double tap of PLAY_PAUSE is the next track instead of changing PLAY/PAUSE. 406 sessionCallback.reset(2); 407 setPlaybackState(PlaybackState.STATE_PLAYING); 408 simulateMediaKeyInput(KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE); 409 simulateMediaKeyInput(KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE); 410 assertFalse(sessionCallback.await(WAIT_MS)); 411 assertTrue(sessionCallback.mOnSkipToNextCalled); 412 assertEquals(0, sessionCallback.mOnPlayCalledCount); 413 assertFalse(sessionCallback.mOnPauseCalled); 414 assertTrue(compareRemoteUserInfo(mKeyDispatcherInfo, sessionCallback.mCallerInfo)); 415 416 // Test if PLAY_PAUSE double tap is considered as two single taps when another media 417 // key is pressed. 418 sessionCallback.reset(3); 419 setPlaybackState(PlaybackState.STATE_PAUSED); 420 simulateMediaKeyInput(KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE); 421 simulateMediaKeyInput(KeyEvent.KEYCODE_MEDIA_STOP); 422 simulateMediaKeyInput(KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE); 423 assertTrue(sessionCallback.await(TIME_OUT_MS)); 424 assertEquals(2, sessionCallback.mOnPlayCalledCount); 425 assertTrue(sessionCallback.mOnStopCalled); 426 assertTrue(compareRemoteUserInfo(mKeyDispatcherInfo, sessionCallback.mCallerInfo)); 427 428 // Test if media keys are handled in order. 429 sessionCallback.reset(2); 430 setPlaybackState(PlaybackState.STATE_PAUSED); 431 simulateMediaKeyInput(KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE); 432 simulateMediaKeyInput(KeyEvent.KEYCODE_MEDIA_STOP); 433 assertTrue(sessionCallback.await(TIME_OUT_MS)); 434 assertEquals(1, sessionCallback.mOnPlayCalledCount); 435 assertTrue(sessionCallback.mOnStopCalled); 436 assertTrue(compareRemoteUserInfo(mKeyDispatcherInfo, sessionCallback.mCallerInfo)); 437 synchronized (mWaitLock) { 438 assertEquals(PlaybackState.STATE_STOPPED, 439 mSession.getController().getPlaybackState().getState()); 440 } 441 } 442 443 /** 444 * Tests {@link MediaSession#setCallback} with {@code null}. No callbacks will be called 445 * once {@code setCallback(null)} is done. 446 */ testSetCallbackWithNull()447 public void testSetCallbackWithNull() throws Exception { 448 MediaSessionCallback sessionCallback = new MediaSessionCallback(); 449 mSession.setCallback(sessionCallback, mHandler); 450 mSession.setFlags(MediaSession.FLAG_HANDLES_TRANSPORT_CONTROLS); 451 mSession.setActive(true); 452 453 MediaController controller = mSession.getController(); 454 setPlaybackState(PlaybackState.STATE_PLAYING); 455 456 sessionCallback.reset(1); 457 mSession.setCallback(null, mHandler); 458 459 controller.getTransportControls().pause(); 460 assertFalse(sessionCallback.await(WAIT_MS)); 461 assertFalse("Callback shouldn't be called.", sessionCallback.mOnPauseCalled); 462 } 463 setPlaybackState(int state)464 private void setPlaybackState(int state) { 465 final long allActions = PlaybackState.ACTION_PLAY | PlaybackState.ACTION_PAUSE 466 | PlaybackState.ACTION_PLAY_PAUSE | PlaybackState.ACTION_STOP 467 | PlaybackState.ACTION_SKIP_TO_NEXT | PlaybackState.ACTION_SKIP_TO_PREVIOUS 468 | PlaybackState.ACTION_FAST_FORWARD | PlaybackState.ACTION_REWIND; 469 PlaybackState playbackState = new PlaybackState.Builder().setActions(allActions) 470 .setState(state, 0L, 0.0f).build(); 471 synchronized (mWaitLock) { 472 mSession.setPlaybackState(playbackState); 473 } 474 } 475 476 /** 477 * Test {@link MediaSession#release} doesn't crash when multiple media sessions are in the app 478 * which receives the media key events. 479 * See: b/36669550 480 */ testReleaseNoCrashWithMultipleSessions()481 public void testReleaseNoCrashWithMultipleSessions() throws Exception { 482 // Start a media playback for this app to receive media key events. 483 Utils.assertMediaPlaybackStarted(getContext()); 484 485 MediaSession anotherSession = new MediaSession(getContext(), TEST_SESSION_TAG); 486 mSession.release(); 487 anotherSession.release(); 488 489 // Try release with the different order. 490 mSession = new MediaSession(getContext(), TEST_SESSION_TAG); 491 anotherSession = new MediaSession(getContext(), TEST_SESSION_TAG); 492 anotherSession.release(); 493 mSession.release(); 494 } 495 496 // This uses public APIs to dispatch key events, so sessions would consider this as 497 // 'media key event from this application'. simulateMediaKeyInput(int keyCode)498 private void simulateMediaKeyInput(int keyCode) { 499 mAudioManager.dispatchMediaKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, keyCode)); 500 mAudioManager.dispatchMediaKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, keyCode)); 501 } 502 503 /** 504 * Tests {@link MediaSession.QueueItem}. 505 */ testQueueItem()506 public void testQueueItem() { 507 MediaDescription.Builder descriptionBuilder = new MediaDescription.Builder() 508 .setMediaId("media-id") 509 .setTitle("title"); 510 511 QueueItem item = new QueueItem(descriptionBuilder.build(), TEST_QUEUE_ID); 512 assertEquals(TEST_QUEUE_ID, item.getQueueId()); 513 assertEquals("media-id", item.getDescription().getMediaId()); 514 assertEquals("title", item.getDescription().getTitle()); 515 assertEquals(0, item.describeContents()); 516 517 QueueItem sameItem = new QueueItem(descriptionBuilder.build(), TEST_QUEUE_ID); 518 assertTrue(item.equals(sameItem)); 519 520 QueueItem differentQueueId = new QueueItem( 521 descriptionBuilder.build(), TEST_QUEUE_ID + 1); 522 assertFalse(item.equals(differentQueueId)); 523 524 QueueItem differentDescription = new QueueItem( 525 descriptionBuilder.setTitle("title2").build(), TEST_QUEUE_ID); 526 assertFalse(item.equals(differentDescription)); 527 528 Parcel p = Parcel.obtain(); 529 item.writeToParcel(p, 0); 530 p.setDataPosition(0); 531 QueueItem other = QueueItem.CREATOR.createFromParcel(p); 532 assertEquals(item.toString(), other.toString()); 533 p.recycle(); 534 } 535 testSessionInfoWithFrameworkParcelable()536 public void testSessionInfoWithFrameworkParcelable() { 537 final String testKey = "test_key"; 538 final AudioAttributes frameworkParcelable = new AudioAttributes.Builder().build(); 539 540 Bundle sessionInfo = new Bundle(); 541 sessionInfo.putParcelable(testKey, frameworkParcelable); 542 543 MediaSession session = null; 544 try { 545 session = new MediaSession( 546 mContext, "testSessionInfoWithFrameworkParcelable", sessionInfo); 547 Bundle sessionInfoOut = session.getController().getSessionInfo(); 548 assertTrue(sessionInfoOut.containsKey(testKey)); 549 assertEquals(frameworkParcelable, sessionInfoOut.getParcelable(testKey)); 550 } finally { 551 if (session != null) { 552 session.release(); 553 } 554 } 555 556 } 557 testSessionInfoWithCustomParcelable()558 public void testSessionInfoWithCustomParcelable() { 559 final String testKey = "test_key"; 560 final MediaSession2Test.CustomParcelable customParcelable = 561 new MediaSession2Test.CustomParcelable(1); 562 563 Bundle sessionInfo = new Bundle(); 564 sessionInfo.putParcelable(testKey, customParcelable); 565 566 try { 567 MediaSession session = new MediaSession( 568 mContext, "testSessionInfoWithCustomParcelable", sessionInfo); 569 fail("Custom Parcelable shouldn't be accepted!"); 570 } catch (IllegalArgumentException e) { 571 // Expected 572 } 573 } 574 575 /** 576 * Verifies that a new session hasn't had any configuration bits set yet. 577 * 578 * @param controller The controller for the session 579 */ verifyNewSession(MediaController controller)580 private void verifyNewSession(MediaController controller) { 581 assertEquals("New session has unexpected configuration", 0L, controller.getFlags()); 582 assertNull("New session has unexpected configuration", controller.getExtras()); 583 assertNull("New session has unexpected configuration", controller.getMetadata()); 584 assertEquals("New session has unexpected configuration", 585 getContext().getPackageName(), controller.getPackageName()); 586 assertNull("New session has unexpected configuration", controller.getPlaybackState()); 587 assertNull("New session has unexpected configuration", controller.getQueue()); 588 assertNull("New session has unexpected configuration", controller.getQueueTitle()); 589 assertEquals("New session has unexpected configuration", Rating.RATING_NONE, 590 controller.getRatingType()); 591 assertNull("New session has unexpected configuration", controller.getSessionActivity()); 592 593 assertNotNull(controller.getSessionToken()); 594 assertNotNull(controller.getTransportControls()); 595 596 MediaController.PlaybackInfo info = controller.getPlaybackInfo(); 597 assertNotNull(info); 598 assertEquals(MediaController.PlaybackInfo.PLAYBACK_TYPE_LOCAL, info.getPlaybackType()); 599 AudioAttributes attrs = info.getAudioAttributes(); 600 assertNotNull(attrs); 601 assertEquals(AudioAttributes.USAGE_MEDIA, attrs.getUsage()); 602 assertEquals(mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC), 603 info.getCurrentVolume()); 604 } 605 606 private class MediaControllerCallback extends MediaController.Callback { 607 private volatile boolean mOnPlaybackStateChangedCalled; 608 private volatile boolean mOnMetadataChangedCalled; 609 private volatile boolean mOnQueueChangedCalled; 610 private volatile boolean mOnQueueTitleChangedCalled; 611 private volatile boolean mOnExtraChangedCalled; 612 private volatile boolean mOnAudioInfoChangedCalled; 613 private volatile boolean mOnSessionDestroyedCalled; 614 private volatile boolean mOnSessionEventCalled; 615 616 private volatile PlaybackState mPlaybackState; 617 private volatile MediaMetadata mMediaMetadata; 618 private volatile List<QueueItem> mQueue; 619 private volatile CharSequence mTitle; 620 private volatile String mEvent; 621 private volatile Bundle mExtras; 622 private volatile MediaController.PlaybackInfo mPlaybackInfo; 623 resetLocked()624 public void resetLocked() { 625 mOnPlaybackStateChangedCalled = false; 626 mOnMetadataChangedCalled = false; 627 mOnQueueChangedCalled = false; 628 mOnQueueTitleChangedCalled = false; 629 mOnExtraChangedCalled = false; 630 mOnAudioInfoChangedCalled = false; 631 mOnSessionDestroyedCalled = false; 632 mOnSessionEventCalled = false; 633 634 mPlaybackState = null; 635 mMediaMetadata = null; 636 mQueue = null; 637 mTitle = null; 638 mExtras = null; 639 mPlaybackInfo = null; 640 } 641 642 @Override onPlaybackStateChanged(PlaybackState state)643 public void onPlaybackStateChanged(PlaybackState state) { 644 synchronized (mWaitLock) { 645 mOnPlaybackStateChangedCalled = true; 646 mPlaybackState = state; 647 mWaitLock.notify(); 648 } 649 } 650 651 @Override onMetadataChanged(MediaMetadata metadata)652 public void onMetadataChanged(MediaMetadata metadata) { 653 synchronized (mWaitLock) { 654 mOnMetadataChangedCalled = true; 655 mMediaMetadata = metadata; 656 mWaitLock.notify(); 657 } 658 } 659 660 @Override onQueueChanged(List<QueueItem> queue)661 public void onQueueChanged(List<QueueItem> queue) { 662 synchronized (mWaitLock) { 663 mOnQueueChangedCalled = true; 664 mQueue = queue; 665 mWaitLock.notify(); 666 } 667 } 668 669 @Override onQueueTitleChanged(CharSequence title)670 public void onQueueTitleChanged(CharSequence title) { 671 synchronized (mWaitLock) { 672 mOnQueueTitleChangedCalled = true; 673 mTitle = title; 674 mWaitLock.notify(); 675 } 676 } 677 678 @Override onExtrasChanged(Bundle extras)679 public void onExtrasChanged(Bundle extras) { 680 synchronized (mWaitLock) { 681 mOnExtraChangedCalled = true; 682 mExtras = extras; 683 mWaitLock.notify(); 684 } 685 } 686 687 @Override onAudioInfoChanged(MediaController.PlaybackInfo info)688 public void onAudioInfoChanged(MediaController.PlaybackInfo info) { 689 synchronized (mWaitLock) { 690 mOnAudioInfoChangedCalled = true; 691 mPlaybackInfo = info; 692 mWaitLock.notify(); 693 } 694 } 695 696 @Override onSessionDestroyed()697 public void onSessionDestroyed() { 698 synchronized (mWaitLock) { 699 mOnSessionDestroyedCalled = true; 700 mWaitLock.notify(); 701 } 702 } 703 704 @Override onSessionEvent(String event, Bundle extras)705 public void onSessionEvent(String event, Bundle extras) { 706 synchronized (mWaitLock) { 707 mOnSessionEventCalled = true; 708 mEvent = event; 709 mExtras = (Bundle) extras.clone(); 710 mWaitLock.notify(); 711 } 712 } 713 } 714 715 private class MediaSessionCallback extends MediaSession.Callback { 716 private CountDownLatch mLatch; 717 private int mOnPlayCalledCount; 718 private boolean mOnPauseCalled; 719 private boolean mOnStopCalled; 720 private boolean mOnFastForwardCalled; 721 private boolean mOnRewindCalled; 722 private boolean mOnSkipToPreviousCalled; 723 private boolean mOnSkipToNextCalled; 724 private RemoteUserInfo mCallerInfo; 725 reset(int count)726 public void reset(int count) { 727 mLatch = new CountDownLatch(count); 728 mOnPlayCalledCount = 0; 729 mOnPauseCalled = false; 730 mOnStopCalled = false; 731 mOnFastForwardCalled = false; 732 mOnRewindCalled = false; 733 mOnSkipToPreviousCalled = false; 734 mOnSkipToNextCalled = false; 735 } 736 await(long waitMs)737 public boolean await(long waitMs) { 738 try { 739 return mLatch.await(waitMs, TimeUnit.MILLISECONDS); 740 } catch (InterruptedException e) { 741 return false; 742 } 743 } 744 745 @Override onPlay()746 public void onPlay() { 747 mOnPlayCalledCount++; 748 mCallerInfo = mSession.getCurrentControllerInfo(); 749 setPlaybackState(PlaybackState.STATE_PLAYING); 750 mLatch.countDown(); 751 } 752 753 @Override onPause()754 public void onPause() { 755 mOnPauseCalled = true; 756 mCallerInfo = mSession.getCurrentControllerInfo(); 757 setPlaybackState(PlaybackState.STATE_PAUSED); 758 mLatch.countDown(); 759 } 760 761 @Override onStop()762 public void onStop() { 763 mOnStopCalled = true; 764 mCallerInfo = mSession.getCurrentControllerInfo(); 765 setPlaybackState(PlaybackState.STATE_STOPPED); 766 mLatch.countDown(); 767 } 768 769 @Override onFastForward()770 public void onFastForward() { 771 mOnFastForwardCalled = true; 772 mCallerInfo = mSession.getCurrentControllerInfo(); 773 mLatch.countDown(); 774 } 775 776 @Override onRewind()777 public void onRewind() { 778 mOnRewindCalled = true; 779 mCallerInfo = mSession.getCurrentControllerInfo(); 780 mLatch.countDown(); 781 } 782 783 @Override onSkipToPrevious()784 public void onSkipToPrevious() { 785 mOnSkipToPreviousCalled = true; 786 mCallerInfo = mSession.getCurrentControllerInfo(); 787 mLatch.countDown(); 788 } 789 790 @Override onSkipToNext()791 public void onSkipToNext() { 792 mOnSkipToNextCalled = true; 793 mCallerInfo = mSession.getCurrentControllerInfo(); 794 mLatch.countDown(); 795 } 796 } 797 } 798