diff options
author | Justin Klaassen <justinklaassen@google.com> | 2018-04-15 00:41:15 -0400 |
---|---|---|
committer | Justin Klaassen <justinklaassen@google.com> | 2018-04-15 00:41:15 -0400 |
commit | b8042fc9b036db0a6692ca853428fc6ab1e60892 (patch) | |
tree | 82669ea5d75238758e22d379a42baeada526219e /androidx/media/MediaSession2Test.java | |
parent | 4d01eeaffaa720e4458a118baa137a11614f00f7 (diff) | |
download | android-28-b8042fc9b036db0a6692ca853428fc6ab1e60892.tar.gz |
Import Android SDK Platform P [4719250]HEADmastermainandroidx-work-releaseandroidx-webkit-releaseandroidx-viewpager2-releaseandroidx-versionedparcelable-releaseandroidx-vectordrawable-releaseandroidx-transition-releaseandroidx-sqlite-releaseandroidx-sharetarget-releaseandroidx-security-security-crypto-releaseandroidx-savedstate-releaseandroidx-room-releaseandroidx-recyclerview-releaseandroidx-recyclerview-recyclerview-selection-releaseandroidx-preference-releaseandroidx-paging-releaseandroidx-paging-legacy-releaseandroidx-navigation-releaseandroidx-mediarouter-releaseandroidx-media2-releaseandroidx-media2-media2-widget-releaseandroidx-media-releaseandroidx-master-releaseandroidx-localbroadcastmanager-releaseandroidx-loader-releaseandroidx-lifecycle-releaseandroidx-jetifier-releaseandroidx-g3-releaseandroidx-fragment-releaseandroidx-exifinterface-releaseandroidx-enterprise-releaseandroidx-core-releaseandroidx-core-core-role-releaseandroidx-coordinatorlayout-releaseandroidx-concurrent-releaseandroidx-compose-releaseandroidx-collection-releaseandroidx-camerax-releaseandroidx-browser-releaseandroidx-biometric-releaseandroidx-benchmark-releaseandroidx-autofill-releaseandroidx-arch-core-releaseandroidx-appcompat-releaseandroidx-annotation-releaseandroidx-annotation-annotation-experimental-releaseandroidx-activity-releaseandroid-arch-work-releaseandroid-arch-navigation-release
/google/data/ro/projects/android/fetch_artifact \
--bid 4719250 \
--target sdk_phone_armv7-win_sdk \
sdk-repo-linux-sources-4719250.zip
AndroidVersion.ApiLevel has been modified to appear as 28
Change-Id: I9ec0a12c9251b8449dba0d86b0cfdbcca16b0a7c
Diffstat (limited to 'androidx/media/MediaSession2Test.java')
-rw-r--r-- | androidx/media/MediaSession2Test.java | 1053 |
1 files changed, 1053 insertions, 0 deletions
diff --git a/androidx/media/MediaSession2Test.java b/androidx/media/MediaSession2Test.java new file mode 100644 index 00000000..5e7ed0e9 --- /dev/null +++ b/androidx/media/MediaSession2Test.java @@ -0,0 +1,1053 @@ +/* + * Copyright 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package androidx.media; + +import static android.media.AudioAttributes.CONTENT_TYPE_MUSIC; + +import static androidx.media.VolumeProviderCompat.VOLUME_CONTROL_ABSOLUTE; +import static androidx.media.VolumeProviderCompat.VOLUME_CONTROL_FIXED; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import android.content.Context; +import android.media.AudioManager; +import android.os.Build; +import android.os.Bundle; +import android.os.Process; +import android.os.ResultReceiver; +import android.support.test.filters.SdkSuppress; +import android.support.test.filters.SmallTest; +import android.support.test.runner.AndroidJUnit4; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.media.MediaController2.ControllerCallback; +import androidx.media.MediaController2.PlaybackInfo; +import androidx.media.MediaSession2.CommandButton; +import androidx.media.MediaSession2.ControllerInfo; +import androidx.media.MediaSession2.SessionCallback; + +import junit.framework.Assert; + +import org.junit.After; +import org.junit.Before; +import org.junit.Ignore; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +/** + * Tests {@link MediaSession2}. + */ +@SdkSuppress(minSdkVersion = Build.VERSION_CODES.KITKAT) +@RunWith(AndroidJUnit4.class) +@SmallTest +public class MediaSession2Test extends MediaSession2TestBase { + private static final String TAG = "MediaSession2Test"; + + private MediaSession2 mSession; + private MockPlayer mPlayer; + private MockPlaylistAgent mMockAgent; + + @Before + @Override + public void setUp() throws Exception { + super.setUp(); + mPlayer = new MockPlayer(0); + mMockAgent = new MockPlaylistAgent(); + + mSession = new MediaSession2.Builder(mContext) + .setPlayer(mPlayer) + .setPlaylistAgent(mMockAgent) + .setSessionCallback(sHandlerExecutor, new SessionCallback() { + @Override + public SessionCommandGroup2 onConnect(MediaSession2 session, + ControllerInfo controller) { + if (Process.myUid() == controller.getUid()) { + return super.onConnect(session, controller); + } + return null; + } + }).build(); + } + + @After + @Override + public void cleanUp() throws Exception { + super.cleanUp(); + mSession.close(); + } + + @Test + public void testBuilder() { + prepareLooper(); + MediaSession2.Builder builder = new MediaSession2.Builder(mContext); + try { + builder.setPlayer(null); + fail("null player shouldn't be allowed"); + } catch (IllegalArgumentException e) { + // expected. pass-through + } + try { + builder.setId(null); + fail("null id shouldn't be allowed"); + } catch (IllegalArgumentException e) { + // expected. pass-through + } + } + + @Test + public void testPlayerStateChange() throws Exception { + prepareLooper(); + final int targetState = MediaPlayerBase.PLAYER_STATE_PLAYING; + final CountDownLatch latchForSessionCallback = new CountDownLatch(1); + sHandler.postAndSync(new Runnable() { + @Override + public void run() { + mSession.close(); + mSession = new MediaSession2.Builder(mContext) + .setPlayer(mPlayer) + .setSessionCallback(sHandlerExecutor, new SessionCallback() { + @Override + public void onPlayerStateChanged(MediaSession2 session, + MediaPlayerBase player, int state) { + assertEquals(targetState, state); + latchForSessionCallback.countDown(); + } + }).build(); + } + }); + + final CountDownLatch latchForControllerCallback = new CountDownLatch(1); + final MediaController2 controller = + createController(mSession.getToken(), true, new ControllerCallback() { + @Override + public void onPlayerStateChanged(MediaController2 controllerOut, int state) { + assertEquals(targetState, state); + latchForControllerCallback.countDown(); + } + }); + + mPlayer.notifyPlaybackState(targetState); + assertTrue(latchForSessionCallback.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS)); + assertTrue(latchForControllerCallback.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS)); + assertEquals(targetState, controller.getPlayerState()); + } + + @Test + public void testBufferingStateChange() throws Exception { + prepareLooper(); + final List<MediaItem2> playlist = TestUtils.createPlaylist(5); + + final MediaItem2 targetItem = playlist.get(3); + final int targetBufferingState = MediaPlayerBase.BUFFERING_STATE_BUFFERING_COMPLETE; + final CountDownLatch latchForSessionCallback = new CountDownLatch(1); + sHandler.postAndSync(new Runnable() { + @Override + public void run() { + mSession.close(); + mMockAgent.setPlaylist(playlist, null); + mSession = new MediaSession2.Builder(mContext) + .setPlayer(mPlayer) + .setPlaylistAgent(mMockAgent) + .setSessionCallback(sHandlerExecutor, new SessionCallback() { + @Override + public void onBufferingStateChanged(MediaSession2 session, + MediaPlayerBase player, MediaItem2 item, int state) { + assertEquals(targetItem, item); + assertEquals(targetBufferingState, state); + latchForSessionCallback.countDown(); + } + }).build(); + } + }); + + final CountDownLatch latchForControllerCallback = new CountDownLatch(1); + final MediaController2 controller = + createController(mSession.getToken(), true, new ControllerCallback() { + @Override + public void onBufferingStateChanged(MediaController2 controller, + MediaItem2 item, int state) { + assertEquals(targetItem, item); + assertEquals(targetBufferingState, state); + latchForControllerCallback.countDown(); + } + }); + + mPlayer.notifyBufferingState(targetItem, targetBufferingState); + assertTrue(latchForSessionCallback.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS)); + assertTrue(latchForControllerCallback.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS)); + assertEquals(targetBufferingState, controller.getBufferingState()); + } + + @Test + public void testCurrentDataSourceChanged() throws Exception { + prepareLooper(); + final int listSize = 5; + final List<MediaItem2> list = TestUtils.createPlaylist(listSize); + mMockAgent.setPlaylist(list, null); + + final MediaItem2 currentItem = list.get(3); + mMockAgent.mCurrentMediaItem = currentItem; + + final CountDownLatch latchForSessionCallback = new CountDownLatch(1); + try (MediaSession2 session = new MediaSession2.Builder(mContext) + .setPlayer(mPlayer) + .setPlaylistAgent(mMockAgent) + .setId("testCurrentDataSourceChanged") + .setSessionCallback(sHandlerExecutor, new SessionCallback() { + @Override + public void onCurrentMediaItemChanged(MediaSession2 session, + MediaPlayerBase player, MediaItem2 itemOut) { + assertSame(currentItem, itemOut); + latchForSessionCallback.countDown(); + } + }).build()) { + + final CountDownLatch latchForControllerCallback = new CountDownLatch(1); + final MediaController2 controller = + createController(mSession.getToken(), true, new ControllerCallback() { + @Override + public void onCurrentMediaItemChanged(MediaController2 controller, + MediaItem2 item) { + assertEquals(currentItem, item); + latchForControllerCallback.countDown(); + } + }); + + mPlayer.notifyCurrentDataSourceChanged(currentItem.getDataSourceDesc()); + assertTrue(latchForSessionCallback.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS)); + assertTrue(latchForControllerCallback.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS)); + assertEquals(currentItem, controller.getCurrentMediaItem()); + } + } + + @Test + public void testMediaPrepared() throws Exception { + prepareLooper(); + final int listSize = 5; + final List<MediaItem2> list = TestUtils.createPlaylist(listSize); + mMockAgent.setPlaylist(list, null); + + final MediaItem2 currentItem = list.get(3); + + final CountDownLatch latchForSessionCallback = new CountDownLatch(1); + try (MediaSession2 session = new MediaSession2.Builder(mContext) + .setPlayer(mPlayer) + .setPlaylistAgent(mMockAgent) + .setId("testMediaPrepared") + .setSessionCallback(sHandlerExecutor, new SessionCallback() { + @Override + public void onMediaPrepared(MediaSession2 session, MediaPlayerBase player, + MediaItem2 itemOut) { + assertSame(currentItem, itemOut); + latchForSessionCallback.countDown(); + } + }).build()) { + + mPlayer.notifyMediaPrepared(currentItem.getDataSourceDesc()); + assertTrue(latchForSessionCallback.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS)); + // TODO(jaewan): Test that controllers are also notified. (b/74505936) + } + } + + @Test + public void testBufferingStateChanged() throws Exception { + prepareLooper(); + final int listSize = 5; + final List<MediaItem2> list = TestUtils.createPlaylist(listSize); + mMockAgent.setPlaylist(list, null); + + final MediaItem2 currentItem = list.get(3); + final int buffState = MediaPlayerBase.BUFFERING_STATE_BUFFERING_COMPLETE; + + final CountDownLatch latchForSessionCallback = new CountDownLatch(1); + try (MediaSession2 session = new MediaSession2.Builder(mContext) + .setPlayer(mPlayer) + .setPlaylistAgent(mMockAgent) + .setId("testBufferingStateChanged") + .setSessionCallback(sHandlerExecutor, new SessionCallback() { + @Override + public void onBufferingStateChanged(MediaSession2 session, + MediaPlayerBase player, MediaItem2 itemOut, int stateOut) { + assertSame(currentItem, itemOut); + assertEquals(buffState, stateOut); + latchForSessionCallback.countDown(); + } + }).build()) { + + mPlayer.notifyBufferingStateChanged(currentItem.getDataSourceDesc(), buffState); + assertTrue(latchForSessionCallback.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS)); + // TODO(jaewan): Test that controllers are also notified. (b/74505936) + } + } + + /** + * This also tests {@link ControllerCallback#onPlaybackSpeedChanged(MediaController2, float)} + * and {@link MediaController2#getPlaybackSpeed()}. + */ + @Test + public void testPlaybackSpeedChanged() throws Exception { + prepareLooper(); + final float speed = 1.5f; + mPlayer.setPlaybackSpeed(speed); + + final CountDownLatch latchForSessionCallback = new CountDownLatch(1); + try (MediaSession2 session = new MediaSession2.Builder(mContext) + .setPlayer(mPlayer) + .setId("testPlaybackSpeedChanged") + .setSessionCallback(sHandlerExecutor, new SessionCallback() { + @Override + public void onPlaybackSpeedChanged(MediaSession2 session, + MediaPlayerBase player, float speedOut) { + assertEquals(speed, speedOut, 0.0f); + latchForSessionCallback.countDown(); + } + }).build()) { + + final CountDownLatch latchForControllerCallback = new CountDownLatch(1); + final MediaController2 controller = + createController(mSession.getToken(), true, new ControllerCallback() { + @Override + public void onPlaybackSpeedChanged(MediaController2 controller, + float speedOut) { + assertEquals(speed, speedOut, 0.0f); + latchForControllerCallback.countDown(); + } + }); + + mPlayer.notifyPlaybackSpeedChanged(speed); + assertTrue(latchForSessionCallback.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS)); + assertTrue(latchForControllerCallback.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS)); + assertEquals(speed, controller.getPlaybackSpeed(), 0.0f); + } + } + + @Test + public void testUpdatePlayer() throws Exception { + prepareLooper(); + final int targetState = MediaPlayerBase.PLAYER_STATE_PLAYING; + final CountDownLatch latch = new CountDownLatch(1); + sHandler.postAndSync(new Runnable() { + @Override + public void run() { + mSession.close(); + mSession = new MediaSession2.Builder(mContext).setPlayer(mPlayer) + .setSessionCallback(sHandlerExecutor, new SessionCallback() { + @Override + public void onPlayerStateChanged(MediaSession2 session, + MediaPlayerBase player, int state) { + assertEquals(targetState, state); + latch.countDown(); + } + }).build(); + } + }); + + MockPlayer player = new MockPlayer(0); + + // Test if setPlayer doesn't crash with various situations. + mSession.updatePlayer(mPlayer, null, null); + assertEquals(mPlayer, mSession.getPlayer()); + MediaPlaylistAgent agent = mSession.getPlaylistAgent(); + assertNotNull(agent); + + mSession.updatePlayer(player, null, null); + assertEquals(player, mSession.getPlayer()); + assertNotNull(mSession.getPlaylistAgent()); + assertNotEquals(agent, mSession.getPlaylistAgent()); + + player.notifyPlaybackState(MediaPlayerBase.PLAYER_STATE_PLAYING); + assertTrue(latch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS)); + } + + @Test + public void testSetPlayer_playbackInfo() throws Exception { + prepareLooper(); + MockPlayer player = new MockPlayer(0); + final AudioAttributesCompat attrs = new AudioAttributesCompat.Builder() + .setContentType(CONTENT_TYPE_MUSIC) + .build(); + player.setAudioAttributes(attrs); + + final int maxVolume = 100; + final int currentVolume = 23; + final int volumeControlType = VOLUME_CONTROL_ABSOLUTE; + VolumeProviderCompat volumeProvider = new VolumeProviderCompat( + volumeControlType, maxVolume, currentVolume) { }; + + final CountDownLatch latch = new CountDownLatch(1); + final ControllerCallback callback = new ControllerCallback() { + @Override + public void onPlaybackInfoChanged(MediaController2 controller, PlaybackInfo info) { + Assert.assertEquals(PlaybackInfo.PLAYBACK_TYPE_REMOTE, info.getPlaybackType()); + assertEquals(attrs, info.getAudioAttributes()); + assertEquals(volumeControlType, info.getPlaybackType()); + assertEquals(maxVolume, info.getMaxVolume()); + assertEquals(currentVolume, info.getCurrentVolume()); + latch.countDown(); + } + }; + + mSession.updatePlayer(player, null, null); + + final MediaController2 controller = createController(mSession.getToken(), true, callback); + PlaybackInfo info = controller.getPlaybackInfo(); + assertNotNull(info); + assertEquals(PlaybackInfo.PLAYBACK_TYPE_LOCAL, info.getPlaybackType()); + assertEquals(attrs, info.getAudioAttributes()); + AudioManager manager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE); + + int localVolumeControlType = VOLUME_CONTROL_ABSOLUTE; + if (Build.VERSION.SDK_INT >= 21 && manager.isVolumeFixed()) { + localVolumeControlType = VOLUME_CONTROL_FIXED; + } + assertEquals(localVolumeControlType, info.getControlType()); + assertEquals(manager.getStreamMaxVolume(AudioManager.STREAM_MUSIC), info.getMaxVolume()); + assertEquals(manager.getStreamVolume(AudioManager.STREAM_MUSIC), info.getCurrentVolume()); + + mSession.updatePlayer(player, null, volumeProvider); + assertTrue(latch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS)); + + info = controller.getPlaybackInfo(); + assertNotNull(info); + assertEquals(PlaybackInfo.PLAYBACK_TYPE_REMOTE, info.getPlaybackType()); + assertEquals(attrs, info.getAudioAttributes()); + assertEquals(volumeControlType, info.getControlType()); + assertEquals(maxVolume, info.getMaxVolume()); + assertEquals(currentVolume, info.getCurrentVolume()); + } + + @Test + public void testPlay() throws Exception { + prepareLooper(); + mSession.play(); + assertTrue(mPlayer.mPlayCalled); + } + + @Test + public void testPause() throws Exception { + prepareLooper(); + mSession.pause(); + assertTrue(mPlayer.mPauseCalled); + } + + @Test + public void testReset() throws Exception { + prepareLooper(); + mSession.reset(); + assertTrue(mPlayer.mResetCalled); + } + + @Test + public void testPrepare() throws Exception { + prepareLooper(); + mSession.prepare(); + assertTrue(mPlayer.mPrepareCalled); + } + + @Test + public void testSeekTo() throws Exception { + prepareLooper(); + final long pos = 1004L; + mSession.seekTo(pos); + assertTrue(mPlayer.mSeekToCalled); + assertEquals(pos, mPlayer.mSeekPosition); + } + + @Test + public void testSetPlaybackSpeed() throws Exception { + prepareLooper(); + final float speed = 1.5f; + mSession.setPlaybackSpeed(speed); + assertTrue(mPlayer.mSetPlaybackSpeedCalled); + assertEquals(speed, mPlayer.mPlaybackSpeed, 0.0f); + } + + @Test + public void testGetPlaybackSpeed() throws Exception { + prepareLooper(); + final float speed = 1.5f; + mPlayer.setPlaybackSpeed(speed); + assertEquals(speed, mSession.getPlaybackSpeed(), 0.0f); + } + + @Test + public void testGetCurrentMediaItem() { + prepareLooper(); + MediaItem2 item = TestUtils.createMediaItemWithMetadata(); + mMockAgent.mCurrentMediaItem = item; + assertEquals(item, mSession.getCurrentMediaItem()); + } + + @Test + public void testSkipToPreviousItem() { + prepareLooper(); + mSession.skipToPreviousItem(); + assertTrue(mMockAgent.mSkipToPreviousItemCalled); + } + + @Test + public void testSkipToNextItem() throws Exception { + prepareLooper(); + mSession.skipToNextItem(); + assertTrue(mMockAgent.mSkipToNextItemCalled); + } + + @Test + public void testSkipToPlaylistItem() throws Exception { + prepareLooper(); + final MediaItem2 testMediaItem = TestUtils.createMediaItemWithMetadata(); + mSession.skipToPlaylistItem(testMediaItem); + assertTrue(mMockAgent.mSkipToPlaylistItemCalled); + assertSame(testMediaItem, mMockAgent.mItem); + } + + @Test + public void testGetPlayerState() { + prepareLooper(); + final int state = MediaPlayerBase.PLAYER_STATE_PLAYING; + mPlayer.mLastPlayerState = state; + assertEquals(state, mSession.getPlayerState()); + } + + @Test + public void testGetBufferingState() { + prepareLooper(); + final int bufferingState = MediaPlayerBase.BUFFERING_STATE_BUFFERING_AND_PLAYABLE; + mPlayer.mLastBufferingState = bufferingState; + assertEquals(bufferingState, mSession.getBufferingState()); + } + + @Test + public void testGetPosition() { + prepareLooper(); + final long position = 150000; + mPlayer.mCurrentPosition = position; + assertEquals(position, mSession.getCurrentPosition()); + } + + @Test + public void testGetBufferedPosition() { + prepareLooper(); + final long bufferedPosition = 900000; + mPlayer.mBufferedPosition = bufferedPosition; + assertEquals(bufferedPosition, mSession.getBufferedPosition()); + } + + @Test + public void testSetPlaylist() { + prepareLooper(); + final List<MediaItem2> list = TestUtils.createPlaylist(2); + mSession.setPlaylist(list, null); + assertTrue(mMockAgent.mSetPlaylistCalled); + assertSame(list, mMockAgent.mPlaylist); + assertNull(mMockAgent.mMetadata); + } + + @Test + public void testGetPlaylist() { + prepareLooper(); + final List<MediaItem2> list = TestUtils.createPlaylist(2); + mMockAgent.mPlaylist = list; + assertEquals(list, mSession.getPlaylist()); + } + + @Test + public void testUpdatePlaylistMetadata() { + prepareLooper(); + final MediaMetadata2 testMetadata = TestUtils.createMetadata(); + mSession.updatePlaylistMetadata(testMetadata); + assertTrue(mMockAgent.mUpdatePlaylistMetadataCalled); + assertSame(testMetadata, mMockAgent.mMetadata); + } + + @Test + public void testGetPlaylistMetadata() { + prepareLooper(); + final MediaMetadata2 testMetadata = TestUtils.createMetadata(); + mMockAgent.mMetadata = testMetadata; + assertEquals(testMetadata, mSession.getPlaylistMetadata()); + } + + @Test + public void testSessionCallback_onPlaylistChanged() throws InterruptedException { + prepareLooper(); + final List<MediaItem2> list = TestUtils.createPlaylist(2); + final CountDownLatch latch = new CountDownLatch(1); + mMockAgent.setPlaylist(list, null); + + final SessionCallback sessionCallback = new SessionCallback() { + @Override + public void onPlaylistChanged(MediaSession2 session, MediaPlaylistAgent playlistAgent, + List<MediaItem2> playlist, MediaMetadata2 metadata) { + assertEquals(mMockAgent, playlistAgent); + assertEquals(list, playlist); + assertNull(metadata); + latch.countDown(); + } + }; + try (MediaSession2 session = new MediaSession2.Builder(mContext) + .setPlayer(mPlayer) + .setPlaylistAgent(mMockAgent) + .setId("testSessionCallback") + .setSessionCallback(sHandlerExecutor, sessionCallback) + .build()) { + mMockAgent.notifyPlaylistChanged(); + assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); + } + } + + @Test + public void testAddPlaylistItem() { + prepareLooper(); + final int testIndex = 12; + final MediaItem2 testMediaItem = TestUtils.createMediaItemWithMetadata(); + mSession.addPlaylistItem(testIndex, testMediaItem); + assertTrue(mMockAgent.mAddPlaylistItemCalled); + assertEquals(testIndex, mMockAgent.mIndex); + assertSame(testMediaItem, mMockAgent.mItem); + } + + @Test + public void testRemovePlaylistItem() { + prepareLooper(); + final MediaItem2 testMediaItem = TestUtils.createMediaItemWithMetadata(); + mSession.removePlaylistItem(testMediaItem); + assertTrue(mMockAgent.mRemovePlaylistItemCalled); + assertSame(testMediaItem, mMockAgent.mItem); + } + + @Test + public void testReplacePlaylistItem() throws InterruptedException { + prepareLooper(); + final int testIndex = 12; + final MediaItem2 testMediaItem = TestUtils.createMediaItemWithMetadata(); + mSession.replacePlaylistItem(testIndex, testMediaItem); + assertTrue(mMockAgent.mReplacePlaylistItemCalled); + assertEquals(testIndex, mMockAgent.mIndex); + assertSame(testMediaItem, mMockAgent.mItem); + } + + /** + * This also tests {@link SessionCallback#onShuffleModeChanged} + */ + @Test + public void testGetShuffleMode() throws InterruptedException { + prepareLooper(); + final int testShuffleMode = MediaPlaylistAgent.SHUFFLE_MODE_GROUP; + mMockAgent.setShuffleMode(testShuffleMode); + + final CountDownLatch latch = new CountDownLatch(1); + final SessionCallback sessionCallback = new SessionCallback() { + @Override + public void onShuffleModeChanged(MediaSession2 session, + MediaPlaylistAgent playlistAgent, int shuffleMode) { + assertEquals(mMockAgent, playlistAgent); + assertEquals(testShuffleMode, shuffleMode); + latch.countDown(); + } + }; + try (MediaSession2 session = new MediaSession2.Builder(mContext) + .setPlayer(mPlayer) + .setPlaylistAgent(mMockAgent) + .setId("testGetShuffleMode") + .setSessionCallback(sHandlerExecutor, sessionCallback) + .build()) { + mMockAgent.notifyShuffleModeChanged(); + assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); + } + } + + @Test + public void testSetShuffleMode() { + prepareLooper(); + final int testShuffleMode = MediaPlaylistAgent.SHUFFLE_MODE_GROUP; + mSession.setShuffleMode(testShuffleMode); + assertTrue(mMockAgent.mSetShuffleModeCalled); + assertEquals(testShuffleMode, mMockAgent.mShuffleMode); + } + + /** + * This also tests {@link SessionCallback#onShuffleModeChanged} + */ + @Test + public void testGetRepeatMode() throws InterruptedException { + prepareLooper(); + final int testRepeatMode = MediaPlaylistAgent.REPEAT_MODE_GROUP; + mMockAgent.setRepeatMode(testRepeatMode); + + final CountDownLatch latch = new CountDownLatch(1); + final SessionCallback sessionCallback = new SessionCallback() { + @Override + public void onRepeatModeChanged(MediaSession2 session, MediaPlaylistAgent playlistAgent, + int repeatMode) { + assertEquals(mMockAgent, playlistAgent); + assertEquals(testRepeatMode, repeatMode); + latch.countDown(); + } + }; + try (MediaSession2 session = new MediaSession2.Builder(mContext) + .setPlayer(mPlayer) + .setPlaylistAgent(mMockAgent) + .setId("testGetRepeatMode") + .setSessionCallback(sHandlerExecutor, sessionCallback) + .build()) { + mMockAgent.notifyRepeatModeChanged(); + assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); + } + } + + @Test + public void testSetRepeatMode() { + prepareLooper(); + final int testRepeatMode = MediaPlaylistAgent.REPEAT_MODE_GROUP; + mSession.setRepeatMode(testRepeatMode); + assertTrue(mMockAgent.mSetRepeatModeCalled); + assertEquals(testRepeatMode, mMockAgent.mRepeatMode); + } + + // TODO(jaewan): Revisit + @Ignore + @Test + public void testBadPlayer() throws InterruptedException { + prepareLooper(); + // TODO(jaewan): Add equivalent tests again + final CountDownLatch latch = new CountDownLatch(4); // expected call + 1 + final BadPlayer player = new BadPlayer(0); + + mSession.updatePlayer(player, null, null); + mSession.updatePlayer(mPlayer, null, null); + player.notifyPlaybackState(MediaPlayerBase.PLAYER_STATE_PAUSED); + assertFalse(latch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS)); + } + + // This bad player will keep push events to the listener that is previously + // registered by session.setPlayer(). + private static class BadPlayer extends MockPlayer { + BadPlayer(int count) { + super(count); + } + + @Override + public void unregisterPlayerEventCallback( + @NonNull MediaPlayerBase.PlayerEventCallback listener) { + // No-op. + } + } + + @Test + public void testOnCommandCallback() throws InterruptedException { + prepareLooper(); + final MockOnCommandCallback callback = new MockOnCommandCallback(); + sHandler.postAndSync(new Runnable() { + @Override + public void run() { + mSession.close(); + mPlayer = new MockPlayer(1); + mSession = new MediaSession2.Builder(mContext).setPlayer(mPlayer) + .setSessionCallback(sHandlerExecutor, callback).build(); + } + }); + MediaController2 controller = createController(mSession.getToken()); + controller.pause(); + assertFalse(mPlayer.mCountDownLatch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS)); + assertFalse(mPlayer.mPauseCalled); + assertEquals(1, callback.commands.size()); + assertEquals(SessionCommand2.COMMAND_CODE_PLAYBACK_PAUSE, + (long) callback.commands.get(0).getCommandCode()); + + controller.play(); + assertTrue(mPlayer.mCountDownLatch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS)); + assertTrue(mPlayer.mPlayCalled); + assertFalse(mPlayer.mPauseCalled); + assertEquals(2, callback.commands.size()); + assertEquals(SessionCommand2.COMMAND_CODE_PLAYBACK_PLAY, + (long) callback.commands.get(1).getCommandCode()); + } + + @Test + public void testOnConnectCallback() throws InterruptedException { + prepareLooper(); + final MockOnConnectCallback sessionCallback = new MockOnConnectCallback(); + sHandler.postAndSync(new Runnable() { + @Override + public void run() { + mSession.close(); + mSession = new MediaSession2.Builder(mContext).setPlayer(mPlayer) + .setSessionCallback(sHandlerExecutor, sessionCallback).build(); + } + }); + MediaController2 controller = createController(mSession.getToken(), false, null); + assertNotNull(controller); + waitForConnect(controller, false); + waitForDisconnect(controller, true); + } + + @Test + public void testOnDisconnectCallback() throws InterruptedException { + prepareLooper(); + final CountDownLatch latch = new CountDownLatch(1); + try (MediaSession2 session = new MediaSession2.Builder(mContext) + .setPlayer(mPlayer) + .setId("testOnDisconnectCallback") + .setSessionCallback(sHandlerExecutor, new SessionCallback() { + @Override + public void onDisconnected(MediaSession2 session, + ControllerInfo controller) { + assertEquals(Process.myUid(), controller.getUid()); + latch.countDown(); + } + }).build()) { + MediaController2 controller = createController(session.getToken()); + controller.close(); + assertTrue(latch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS)); + } + } + + @Test + public void testSetCustomLayout() throws InterruptedException { + prepareLooper(); + final List<CommandButton> buttons = new ArrayList<>(); + buttons.add(new CommandButton.Builder() + .setCommand(new SessionCommand2(SessionCommand2.COMMAND_CODE_PLAYBACK_PLAY)) + .setDisplayName("button").build()); + final CountDownLatch latch = new CountDownLatch(1); + final SessionCallback sessionCallback = new SessionCallback() { + @Override + public SessionCommandGroup2 onConnect(MediaSession2 session, + ControllerInfo controller) { + if (mContext.getPackageName().equals(controller.getPackageName())) { + mSession.setCustomLayout(controller, buttons); + } + return super.onConnect(session, controller); + } + }; + + try (MediaSession2 session = new MediaSession2.Builder(mContext) + .setPlayer(mPlayer) + .setId("testSetCustomLayout") + .setSessionCallback(sHandlerExecutor, sessionCallback) + .build()) { + if (mSession != null) { + mSession.close(); + mSession = session; + } + final ControllerCallback callback = new ControllerCallback() { + @Override + public void onCustomLayoutChanged(MediaController2 controller2, + List<CommandButton> layout) { + assertEquals(layout.size(), buttons.size()); + for (int i = 0; i < layout.size(); i++) { + assertEquals(layout.get(i).getCommand(), buttons.get(i).getCommand()); + assertEquals(layout.get(i).getDisplayName(), + buttons.get(i).getDisplayName()); + } + latch.countDown(); + } + }; + final MediaController2 controller = + createController(session.getToken(), true, callback); + assertTrue(latch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS)); + } + } + + @Test + public void testSetAllowedCommands() throws InterruptedException { + prepareLooper(); + final SessionCommandGroup2 commands = new SessionCommandGroup2(); + commands.addCommand(new SessionCommand2(SessionCommand2.COMMAND_CODE_PLAYBACK_PLAY)); + commands.addCommand(new SessionCommand2(SessionCommand2.COMMAND_CODE_PLAYBACK_PAUSE)); + commands.addCommand(new SessionCommand2(SessionCommand2.COMMAND_CODE_PLAYBACK_RESET)); + + final CountDownLatch latch = new CountDownLatch(1); + final ControllerCallback callback = new ControllerCallback() { + @Override + public void onAllowedCommandsChanged(MediaController2 controller, + SessionCommandGroup2 commandsOut) { + assertNotNull(commandsOut); + Set<SessionCommand2> expected = commands.getCommands(); + Set<SessionCommand2> actual = commandsOut.getCommands(); + + assertNotNull(actual); + assertEquals(expected.size(), actual.size()); + for (SessionCommand2 command : expected) { + assertTrue(actual.contains(command)); + } + latch.countDown(); + } + }; + + final MediaController2 controller = createController(mSession.getToken(), true, callback); + ControllerInfo controllerInfo = getTestControllerInfo(); + assertNotNull(controllerInfo); + + mSession.setAllowedCommands(controllerInfo, commands); + assertTrue(latch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS)); + } + + @Test + public void testSendCustomCommand() throws InterruptedException { + prepareLooper(); + final SessionCommand2 testCommand = new SessionCommand2( + SessionCommand2.COMMAND_CODE_PLAYBACK_PREPARE); + final Bundle testArgs = new Bundle(); + testArgs.putString("args", "testSendCustomAction"); + + final CountDownLatch latch = new CountDownLatch(2); + final ControllerCallback callback = new ControllerCallback() { + @Override + public void onCustomCommand(MediaController2 controller, SessionCommand2 command, + Bundle args, ResultReceiver receiver) { + assertEquals(testCommand, command); + assertTrue(TestUtils.equals(testArgs, args)); + assertNull(receiver); + latch.countDown(); + } + }; + final MediaController2 controller = + createController(mSession.getToken(), true, callback); + // TODO(jaewan): Test with multiple controllers + mSession.sendCustomCommand(testCommand, testArgs); + + ControllerInfo controllerInfo = getTestControllerInfo(); + assertNotNull(controllerInfo); + // TODO(jaewan): Test receivers as well. + mSession.sendCustomCommand(controllerInfo, testCommand, testArgs, null); + assertTrue(latch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS)); + } + + @Test + public void testNotifyError() throws InterruptedException { + prepareLooper(); + final int errorCode = MediaSession2.ERROR_CODE_NOT_AVAILABLE_IN_REGION; + final Bundle extras = new Bundle(); + extras.putString("args", "testNotifyError"); + + final CountDownLatch latch = new CountDownLatch(1); + final ControllerCallback callback = new ControllerCallback() { + @Override + public void onError(MediaController2 controller, int errorCodeOut, Bundle extrasOut) { + assertEquals(errorCode, errorCodeOut); + assertTrue(TestUtils.equals(extras, extrasOut)); + latch.countDown(); + } + }; + final MediaController2 controller = createController(mSession.getToken(), true, callback); + // TODO(jaewan): Test with multiple controllers + mSession.notifyError(errorCode, extras); + assertTrue(latch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS)); + } + + @Test + public void testNotifyRoutesInfoChanged() throws InterruptedException { + prepareLooper(); + final CountDownLatch latch = new CountDownLatch(1); + final ControllerCallback callback = new ControllerCallback() { + @Override + public void onRoutesInfoChanged(@NonNull MediaController2 controller, + @Nullable List<Bundle> routes) { + assertNull(routes); + latch.countDown(); + } + }; + final MediaController2 controller = createController(mSession.getToken(), true, callback); + ControllerInfo controllerInfo = getTestControllerInfo(); + mSession.notifyRoutesInfoChanged(controllerInfo, null); + assertTrue(latch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS)); + } + + private ControllerInfo getTestControllerInfo() { + List<ControllerInfo> controllers = mSession.getConnectedControllers(); + assertNotNull(controllers); + for (int i = 0; i < controllers.size(); i++) { + if (Process.myUid() == controllers.get(i).getUid()) { + return controllers.get(i); + } + } + fail("Failed to get test controller info"); + return null; + } + + public class MockOnConnectCallback extends SessionCallback { + @Override + public SessionCommandGroup2 onConnect(MediaSession2 session, + ControllerInfo controllerInfo) { + if (Process.myUid() != controllerInfo.getUid()) { + return null; + } + assertEquals(mContext.getPackageName(), controllerInfo.getPackageName()); + assertEquals(Process.myUid(), controllerInfo.getUid()); + assertFalse(controllerInfo.isTrusted()); + // Reject all + return null; + } + } + + public class MockOnCommandCallback extends SessionCallback { + public final ArrayList<SessionCommand2> commands = new ArrayList<>(); + + @Override + public boolean onCommandRequest(MediaSession2 session, ControllerInfo controllerInfo, + SessionCommand2 command) { + assertEquals(mContext.getPackageName(), controllerInfo.getPackageName()); + assertEquals(Process.myUid(), controllerInfo.getUid()); + assertFalse(controllerInfo.isTrusted()); + commands.add(command); + if (command.getCommandCode() == SessionCommand2.COMMAND_CODE_PLAYBACK_PAUSE) { + return false; + } + return true; + } + } + + private static void assertMediaItemListEquals(List<MediaItem2> a, List<MediaItem2> b) { + if (a == null || b == null) { + assertEquals(a, b); + } + assertEquals(a.size(), b.size()); + + for (int i = 0; i < a.size(); i++) { + MediaItem2 aItem = a.get(i); + MediaItem2 bItem = b.get(i); + + if (aItem == null || bItem == null) { + assertEquals(aItem, bItem); + continue; + } + + assertEquals(aItem.getMediaId(), bItem.getMediaId()); + assertEquals(aItem.getFlags(), bItem.getFlags()); + TestUtils.equals(aItem.getMetadata().toBundle(), bItem.getMetadata().toBundle()); + + // Note: Here it does not check whether DataSourceDesc are equal, + // since there DataSourceDec is not comparable. + } + } +} |