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 android.app.PendingIntent; 19 import android.content.Context; 20 import android.content.Intent; 21 import android.media.AudioAttributes; 22 import android.media.AudioManager; 23 import android.media.MediaDescription; 24 import android.media.MediaMetadata; 25 import android.media.Rating; 26 import android.media.VolumeProvider; 27 import android.media.session.MediaController; 28 import android.media.session.MediaSession; 29 import android.media.session.MediaSession.QueueItem; 30 import android.media.session.PlaybackState; 31 import android.os.Bundle; 32 import android.os.Handler; 33 import android.os.Looper; 34 import android.os.Message; 35 import android.os.Parcel; 36 import android.test.AndroidTestCase; 37 38 import java.util.ArrayList; 39 import java.util.List; 40 import java.util.Set; 41 42 public class MediaSessionTest extends AndroidTestCase { 43 // The maximum time to wait for an operation. 44 private static final long TIME_OUT_MS = 3000L; 45 private static final int MAX_AUDIO_INFO_CHANGED_CALLBACK_COUNT = 10; 46 private static final String TEST_SESSION_TAG = "test-session-tag"; 47 private static final String TEST_KEY = "test-key"; 48 private static final String TEST_VALUE = "test-val"; 49 private static final String TEST_SESSION_EVENT = "test-session-event"; 50 private static final int TEST_CURRENT_VOLUME = 10; 51 private static final int TEST_MAX_VOLUME = 11; 52 private static final long TEST_QUEUE_ID = 12L; 53 private static final long TEST_ACTION = 55L; 54 55 private AudioManager mAudioManager; 56 private Handler mHandler = new Handler(Looper.getMainLooper()); 57 private Object mWaitLock = new Object(); 58 private MediaControllerCallback mCallback = new MediaControllerCallback(); 59 private MediaSession mSession; 60 61 @Override setUp()62 protected void setUp() throws Exception { 63 super.setUp(); 64 mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE); 65 mSession = new MediaSession(getContext(), TEST_SESSION_TAG); 66 } 67 68 @Override tearDown()69 protected void tearDown() throws Exception { 70 // It is OK to call release() twice. 71 mSession.release(); 72 super.tearDown(); 73 } 74 75 /** 76 * Tests that a session can be created and that all the fields are 77 * initialized correctly. 78 */ testCreateSession()79 public void testCreateSession() throws Exception { 80 assertNotNull(mSession.getSessionToken()); 81 assertFalse("New session should not be active", mSession.isActive()); 82 83 // Verify by getting the controller and checking all its fields 84 MediaController controller = mSession.getController(); 85 assertNotNull(controller); 86 verifyNewSession(controller, TEST_SESSION_TAG); 87 } 88 89 /** 90 * Tests MediaSession.Token created in the constructor of MediaSession. 91 */ testSessionToken()92 public void testSessionToken() throws Exception { 93 MediaSession.Token sessionToken = mSession.getSessionToken(); 94 95 assertNotNull(sessionToken); 96 assertEquals(0, sessionToken.describeContents()); 97 98 // Test writeToParcel 99 Parcel p = Parcel.obtain(); 100 sessionToken.writeToParcel(p, 0); 101 p.setDataPosition(0); 102 MediaSession.Token token = MediaSession.Token.CREATOR.createFromParcel(p); 103 assertEquals(token, sessionToken); 104 p.recycle(); 105 } 106 107 /** 108 * Tests that the various configuration bits on a session get passed to the 109 * controller. 110 */ testConfigureSession()111 public void testConfigureSession() throws Exception { 112 MediaController controller = mSession.getController(); 113 controller.registerCallback(mCallback, mHandler); 114 115 synchronized (mWaitLock) { 116 // test setExtras 117 mCallback.resetLocked(); 118 final Bundle extras = new Bundle(); 119 extras.putString(TEST_KEY, TEST_VALUE); 120 mSession.setExtras(extras); 121 mWaitLock.wait(TIME_OUT_MS); 122 assertTrue(mCallback.mOnExtraChangedCalled); 123 124 Bundle extrasOut = mCallback.mExtras; 125 assertNotNull(extrasOut); 126 assertEquals(TEST_VALUE, extrasOut.get(TEST_KEY)); 127 128 extrasOut = controller.getExtras(); 129 assertNotNull(extrasOut); 130 assertEquals(TEST_VALUE, extrasOut.get(TEST_KEY)); 131 132 // test setFlags 133 mSession.setFlags(5); 134 assertEquals(5, controller.getFlags()); 135 136 // test setMetadata 137 mCallback.resetLocked(); 138 MediaMetadata metadata = 139 new MediaMetadata.Builder().putString(TEST_KEY, TEST_VALUE).build(); 140 mSession.setMetadata(metadata); 141 mWaitLock.wait(TIME_OUT_MS); 142 assertTrue(mCallback.mOnMetadataChangedCalled); 143 144 MediaMetadata metadataOut = mCallback.mMediaMetadata; 145 assertNotNull(metadataOut); 146 assertEquals(TEST_VALUE, metadataOut.getString(TEST_KEY)); 147 148 metadataOut = controller.getMetadata(); 149 assertNotNull(metadataOut); 150 assertEquals(TEST_VALUE, metadataOut.getString(TEST_KEY)); 151 152 // test setPlaybackState 153 mCallback.resetLocked(); 154 PlaybackState state = new PlaybackState.Builder().setActions(TEST_ACTION).build(); 155 mSession.setPlaybackState(state); 156 mWaitLock.wait(TIME_OUT_MS); 157 assertTrue(mCallback.mOnPlaybackStateChangedCalled); 158 159 PlaybackState stateOut = mCallback.mPlaybackState; 160 assertNotNull(stateOut); 161 assertEquals(TEST_ACTION, stateOut.getActions()); 162 163 stateOut = controller.getPlaybackState(); 164 assertNotNull(stateOut); 165 assertEquals(TEST_ACTION, stateOut.getActions()); 166 167 // test setQueue and setQueueTitle 168 mCallback.resetLocked(); 169 List<QueueItem> queue = new ArrayList<>(); 170 QueueItem item = new QueueItem(new MediaDescription.Builder() 171 .setMediaId(TEST_VALUE).setTitle("title").build(), TEST_QUEUE_ID); 172 queue.add(item); 173 mSession.setQueue(queue); 174 mWaitLock.wait(TIME_OUT_MS); 175 assertTrue(mCallback.mOnQueueChangedCalled); 176 177 mSession.setQueueTitle(TEST_VALUE); 178 mWaitLock.wait(TIME_OUT_MS); 179 assertTrue(mCallback.mOnQueueTitleChangedCalled); 180 181 assertEquals(TEST_VALUE, mCallback.mTitle); 182 assertEquals(queue.size(), mCallback.mQueue.size()); 183 assertEquals(TEST_QUEUE_ID, mCallback.mQueue.get(0).getQueueId()); 184 assertEquals(TEST_VALUE, mCallback.mQueue.get(0).getDescription().getMediaId()); 185 186 assertEquals(TEST_VALUE, controller.getQueueTitle()); 187 assertEquals(queue.size(), controller.getQueue().size()); 188 assertEquals(TEST_QUEUE_ID, controller.getQueue().get(0).getQueueId()); 189 assertEquals(TEST_VALUE, controller.getQueue().get(0).getDescription().getMediaId()); 190 191 mCallback.resetLocked(); 192 mSession.setQueue(null); 193 mWaitLock.wait(TIME_OUT_MS); 194 assertTrue(mCallback.mOnQueueChangedCalled); 195 196 mSession.setQueueTitle(null); 197 mWaitLock.wait(TIME_OUT_MS); 198 assertTrue(mCallback.mOnQueueTitleChangedCalled); 199 200 assertNull(mCallback.mTitle); 201 assertNull(mCallback.mQueue); 202 assertNull(controller.getQueueTitle()); 203 assertNull(controller.getQueue()); 204 205 // test setSessionActivity 206 Intent intent = new Intent("cts.MEDIA_SESSION_ACTION"); 207 PendingIntent pi = PendingIntent.getActivity(getContext(), 555, intent, 0); 208 mSession.setSessionActivity(pi); 209 assertEquals(pi, controller.getSessionActivity()); 210 211 // test setActivity 212 mSession.setActive(true); 213 assertTrue(mSession.isActive()); 214 215 // test sendSessionEvent 216 mCallback.resetLocked(); 217 mSession.sendSessionEvent(TEST_SESSION_EVENT, extras); 218 mWaitLock.wait(TIME_OUT_MS); 219 220 assertTrue(mCallback.mOnSessionEventCalled); 221 assertEquals(TEST_SESSION_EVENT, mCallback.mEvent); 222 assertEquals(TEST_VALUE, mCallback.mExtras.getString(TEST_KEY)); 223 224 // test release 225 mCallback.resetLocked(); 226 mSession.release(); 227 mWaitLock.wait(TIME_OUT_MS); 228 assertTrue(mCallback.mOnSessionDestroyedCalled); 229 } 230 } 231 232 /** 233 * Tests for setPlaybackToLocal and setPlaybackToRemote. 234 */ testPlaybackToLocalAndRemote()235 public void testPlaybackToLocalAndRemote() throws Exception { 236 MediaController controller = mSession.getController(); 237 controller.registerCallback(mCallback, mHandler); 238 239 synchronized (mWaitLock) { 240 // test setPlaybackToRemote, do this before testing setPlaybackToLocal 241 // to ensure it switches correctly. 242 mCallback.resetLocked(); 243 try { 244 mSession.setPlaybackToRemote(null); 245 fail("Expected IAE for setPlaybackToRemote(null)"); 246 } catch (IllegalArgumentException e) { 247 // expected 248 } 249 VolumeProvider vp = new VolumeProvider(VolumeProvider.VOLUME_CONTROL_FIXED, 250 TEST_MAX_VOLUME, TEST_CURRENT_VOLUME) {}; 251 mSession.setPlaybackToRemote(vp); 252 253 MediaController.PlaybackInfo info = null; 254 for (int i = 0; i < MAX_AUDIO_INFO_CHANGED_CALLBACK_COUNT; ++i) { 255 mCallback.mOnAudioInfoChangedCalled = false; 256 mWaitLock.wait(TIME_OUT_MS); 257 assertTrue(mCallback.mOnAudioInfoChangedCalled); 258 info = mCallback.mPlaybackInfo; 259 if (info != null && info.getCurrentVolume() == TEST_CURRENT_VOLUME 260 && info.getMaxVolume() == TEST_MAX_VOLUME 261 && info.getVolumeControl() == VolumeProvider.VOLUME_CONTROL_FIXED 262 && info.getPlaybackType() 263 == MediaController.PlaybackInfo.PLAYBACK_TYPE_REMOTE) { 264 break; 265 } 266 } 267 assertNotNull(info); 268 assertEquals(MediaController.PlaybackInfo.PLAYBACK_TYPE_REMOTE, info.getPlaybackType()); 269 assertEquals(TEST_MAX_VOLUME, info.getMaxVolume()); 270 assertEquals(TEST_CURRENT_VOLUME, info.getCurrentVolume()); 271 assertEquals(VolumeProvider.VOLUME_CONTROL_FIXED, info.getVolumeControl()); 272 273 info = controller.getPlaybackInfo(); 274 assertNotNull(info); 275 assertEquals(MediaController.PlaybackInfo.PLAYBACK_TYPE_REMOTE, info.getPlaybackType()); 276 assertEquals(TEST_MAX_VOLUME, info.getMaxVolume()); 277 assertEquals(TEST_CURRENT_VOLUME, info.getCurrentVolume()); 278 assertEquals(VolumeProvider.VOLUME_CONTROL_FIXED, info.getVolumeControl()); 279 280 // test setPlaybackToLocal 281 AudioAttributes attrs = new AudioAttributes.Builder().addTag(TEST_VALUE).build(); 282 mSession.setPlaybackToLocal(attrs); 283 284 info = controller.getPlaybackInfo(); 285 assertNotNull(info); 286 assertEquals(MediaController.PlaybackInfo.PLAYBACK_TYPE_LOCAL, info.getPlaybackType()); 287 Set<String> tags = info.getAudioAttributes().getTags(); 288 assertNotNull(tags); 289 assertTrue(tags.contains(TEST_VALUE)); 290 } 291 } 292 293 /** 294 * Tests MediaSession.QueueItem. 295 */ testQueueItem()296 public void testQueueItem() { 297 QueueItem item = new QueueItem(new MediaDescription.Builder() 298 .setMediaId("media-id").setTitle("title").build(), TEST_QUEUE_ID); 299 assertEquals(TEST_QUEUE_ID, item.getQueueId()); 300 assertEquals("media-id", item.getDescription().getMediaId()); 301 assertEquals("title", item.getDescription().getTitle()); 302 303 Parcel p = Parcel.obtain(); 304 item.writeToParcel(p, 0); 305 p.setDataPosition(0); 306 QueueItem other = QueueItem.CREATOR.createFromParcel(p); 307 assertEquals(item.toString(), other.toString()); 308 p.recycle(); 309 } 310 311 /** 312 * Verifies that a new session hasn't had any configuration bits set yet. 313 * 314 * @param controller The controller for the session 315 */ verifyNewSession(MediaController controller, String tag)316 private void verifyNewSession(MediaController controller, String tag) { 317 assertEquals("New session has unexpected configuration", 0L, controller.getFlags()); 318 assertNull("New session has unexpected configuration", controller.getExtras()); 319 assertNull("New session has unexpected configuration", controller.getMetadata()); 320 assertEquals("New session has unexpected configuration", 321 getContext().getPackageName(), controller.getPackageName()); 322 assertNull("New session has unexpected configuration", controller.getPlaybackState()); 323 assertNull("New session has unexpected configuration", controller.getQueue()); 324 assertNull("New session has unexpected configuration", controller.getQueueTitle()); 325 assertEquals("New session has unexpected configuration", Rating.RATING_NONE, 326 controller.getRatingType()); 327 assertNull("New session has unexpected configuration", controller.getSessionActivity()); 328 329 assertNotNull(controller.getSessionToken()); 330 assertNotNull(controller.getTransportControls()); 331 assertEquals(tag, controller.getTag()); 332 333 MediaController.PlaybackInfo info = controller.getPlaybackInfo(); 334 assertNotNull(info); 335 assertEquals(MediaController.PlaybackInfo.PLAYBACK_TYPE_LOCAL, info.getPlaybackType()); 336 AudioAttributes attrs = info.getAudioAttributes(); 337 assertNotNull(attrs); 338 assertEquals(AudioAttributes.USAGE_MEDIA, attrs.getUsage()); 339 assertEquals(mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC), 340 info.getCurrentVolume()); 341 } 342 343 private class MediaControllerCallback extends MediaController.Callback { 344 private volatile boolean mOnPlaybackStateChangedCalled; 345 private volatile boolean mOnMetadataChangedCalled; 346 private volatile boolean mOnQueueChangedCalled; 347 private volatile boolean mOnQueueTitleChangedCalled; 348 private volatile boolean mOnExtraChangedCalled; 349 private volatile boolean mOnAudioInfoChangedCalled; 350 private volatile boolean mOnSessionDestroyedCalled; 351 private volatile boolean mOnSessionEventCalled; 352 353 private volatile PlaybackState mPlaybackState; 354 private volatile MediaMetadata mMediaMetadata; 355 private volatile List<QueueItem> mQueue; 356 private volatile CharSequence mTitle; 357 private volatile String mEvent; 358 private volatile Bundle mExtras; 359 private volatile MediaController.PlaybackInfo mPlaybackInfo; 360 resetLocked()361 public void resetLocked() { 362 mOnPlaybackStateChangedCalled = false; 363 mOnMetadataChangedCalled = false; 364 mOnQueueChangedCalled = false; 365 mOnQueueTitleChangedCalled = false; 366 mOnExtraChangedCalled = false; 367 mOnAudioInfoChangedCalled = false; 368 mOnSessionDestroyedCalled = false; 369 mOnSessionEventCalled = false; 370 371 mPlaybackState = null; 372 mMediaMetadata = null; 373 mQueue = null; 374 mTitle = null; 375 mExtras = null; 376 mPlaybackInfo = null; 377 } 378 379 @Override onPlaybackStateChanged(PlaybackState state)380 public void onPlaybackStateChanged(PlaybackState state) { 381 synchronized (mWaitLock) { 382 mOnPlaybackStateChangedCalled = true; 383 mPlaybackState = state; 384 mWaitLock.notify(); 385 } 386 } 387 388 @Override onMetadataChanged(MediaMetadata metadata)389 public void onMetadataChanged(MediaMetadata metadata) { 390 synchronized (mWaitLock) { 391 mOnMetadataChangedCalled = true; 392 mMediaMetadata = metadata; 393 mWaitLock.notify(); 394 } 395 } 396 397 @Override onQueueChanged(List<QueueItem> queue)398 public void onQueueChanged(List<QueueItem> queue) { 399 synchronized (mWaitLock) { 400 mOnQueueChangedCalled = true; 401 mQueue = queue; 402 mWaitLock.notify(); 403 } 404 } 405 406 @Override onQueueTitleChanged(CharSequence title)407 public void onQueueTitleChanged(CharSequence title) { 408 synchronized (mWaitLock) { 409 mOnQueueTitleChangedCalled = true; 410 mTitle = title; 411 mWaitLock.notify(); 412 } 413 } 414 415 @Override onExtrasChanged(Bundle extras)416 public void onExtrasChanged(Bundle extras) { 417 synchronized (mWaitLock) { 418 mOnExtraChangedCalled = true; 419 mExtras = extras; 420 mWaitLock.notify(); 421 } 422 } 423 424 @Override onAudioInfoChanged(MediaController.PlaybackInfo info)425 public void onAudioInfoChanged(MediaController.PlaybackInfo info) { 426 synchronized (mWaitLock) { 427 mOnAudioInfoChangedCalled = true; 428 mPlaybackInfo = info; 429 mWaitLock.notify(); 430 } 431 } 432 433 @Override onSessionDestroyed()434 public void onSessionDestroyed() { 435 synchronized (mWaitLock) { 436 mOnSessionDestroyedCalled = true; 437 mWaitLock.notify(); 438 } 439 } 440 441 @Override onSessionEvent(String event, Bundle extras)442 public void onSessionEvent(String event, Bundle extras) { 443 synchronized (mWaitLock) { 444 mOnSessionEventCalled = true; 445 mEvent = event; 446 mExtras = (Bundle) extras.clone(); 447 mWaitLock.notify(); 448 } 449 } 450 } 451 } 452