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