Home | History | Annotate | Download | only in cts
      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
     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
     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      */
     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      */
     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      */
    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      */
    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      */
    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      */
    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 
    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
    380         public void onPlaybackStateChanged(PlaybackState state) {
    381             synchronized (mWaitLock) {
    382                 mOnPlaybackStateChangedCalled = true;
    383                 mPlaybackState = state;
    384                 mWaitLock.notify();
    385             }
    386         }
    387 
    388         @Override
    389         public void onMetadataChanged(MediaMetadata metadata) {
    390             synchronized (mWaitLock) {
    391                 mOnMetadataChangedCalled = true;
    392                 mMediaMetadata = metadata;
    393                 mWaitLock.notify();
    394             }
    395         }
    396 
    397         @Override
    398         public void onQueueChanged(List<QueueItem> queue) {
    399             synchronized (mWaitLock) {
    400                 mOnQueueChangedCalled = true;
    401                 mQueue = queue;
    402                 mWaitLock.notify();
    403             }
    404         }
    405 
    406         @Override
    407         public void onQueueTitleChanged(CharSequence title) {
    408             synchronized (mWaitLock) {
    409                 mOnQueueTitleChangedCalled = true;
    410                 mTitle = title;
    411                 mWaitLock.notify();
    412             }
    413         }
    414 
    415         @Override
    416         public void onExtrasChanged(Bundle extras) {
    417             synchronized (mWaitLock) {
    418                 mOnExtraChangedCalled = true;
    419                 mExtras = extras;
    420                 mWaitLock.notify();
    421             }
    422         }
    423 
    424         @Override
    425         public void onAudioInfoChanged(MediaController.PlaybackInfo info) {
    426             synchronized (mWaitLock) {
    427                 mOnAudioInfoChangedCalled = true;
    428                 mPlaybackInfo = info;
    429                 mWaitLock.notify();
    430             }
    431         }
    432 
    433         @Override
    434         public void onSessionDestroyed() {
    435             synchronized (mWaitLock) {
    436                 mOnSessionDestroyedCalled = true;
    437                 mWaitLock.notify();
    438             }
    439         }
    440 
    441         @Override
    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