[go: nahoru, domu]

blob: ecbcaae28b2b2c64b6d544ad46d7ac4da33c84d3 [file] [log] [blame]
/*
* Copyright 2017 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 android.support.mediacompat.service;
import static android.support.mediacompat.testlib.MediaControllerConstants.ADD_QUEUE_ITEM;
import static android.support.mediacompat.testlib.MediaControllerConstants.ADD_QUEUE_ITEM_WITH_CUSTOM_PARCELABLE;
import static android.support.mediacompat.testlib.MediaControllerConstants.ADD_QUEUE_ITEM_WITH_INDEX;
import static android.support.mediacompat.testlib.MediaControllerConstants.ADJUST_VOLUME;
import static android.support.mediacompat.testlib.MediaControllerConstants.DISPATCH_MEDIA_BUTTON;
import static android.support.mediacompat.testlib.MediaControllerConstants.FAST_FORWARD;
import static android.support.mediacompat.testlib.MediaControllerConstants.PAUSE;
import static android.support.mediacompat.testlib.MediaControllerConstants.PLAY;
import static android.support.mediacompat.testlib.MediaControllerConstants.PLAY_FROM_MEDIA_ID;
import static android.support.mediacompat.testlib.MediaControllerConstants.PLAY_FROM_SEARCH;
import static android.support.mediacompat.testlib.MediaControllerConstants.PLAY_FROM_URI;
import static android.support.mediacompat.testlib.MediaControllerConstants.PREPARE;
import static android.support.mediacompat.testlib.MediaControllerConstants.PREPARE_FROM_MEDIA_ID;
import static android.support.mediacompat.testlib.MediaControllerConstants.PREPARE_FROM_SEARCH;
import static android.support.mediacompat.testlib.MediaControllerConstants.PREPARE_FROM_URI;
import static android.support.mediacompat.testlib.MediaControllerConstants.REMOVE_QUEUE_ITEM;
import static android.support.mediacompat.testlib.MediaControllerConstants.REWIND;
import static android.support.mediacompat.testlib.MediaControllerConstants.SEEK_TO;
import static android.support.mediacompat.testlib.MediaControllerConstants.SEND_COMMAND;
import static android.support.mediacompat.testlib.MediaControllerConstants.SEND_CUSTOM_ACTION;
import static android.support.mediacompat.testlib.MediaControllerConstants.SEND_CUSTOM_ACTION_PARCELABLE;
import static android.support.mediacompat.testlib.MediaControllerConstants.SET_CAPTIONING_ENABLED;
import static android.support.mediacompat.testlib.MediaControllerConstants.SET_PLAYBACK_SPEED;
import static android.support.mediacompat.testlib.MediaControllerConstants.SET_RATING;
import static android.support.mediacompat.testlib.MediaControllerConstants.SET_REPEAT_MODE;
import static android.support.mediacompat.testlib.MediaControllerConstants.SET_SHUFFLE_MODE;
import static android.support.mediacompat.testlib.MediaControllerConstants.SET_VOLUME_TO;
import static android.support.mediacompat.testlib.MediaControllerConstants.SKIP_TO_NEXT;
import static android.support.mediacompat.testlib.MediaControllerConstants.SKIP_TO_PREVIOUS;
import static android.support.mediacompat.testlib.MediaControllerConstants.SKIP_TO_QUEUE_ITEM;
import static android.support.mediacompat.testlib.MediaControllerConstants.STOP;
import static android.support.mediacompat.testlib.MediaSessionConstants.TEST_COMMAND;
import static android.support.mediacompat.testlib.MediaSessionConstants.TEST_KEY;
import static android.support.mediacompat.testlib.MediaSessionConstants.TEST_MEDIA_ID_1;
import static android.support.mediacompat.testlib.MediaSessionConstants.TEST_MEDIA_ID_2;
import static android.support.mediacompat.testlib.MediaSessionConstants.TEST_MEDIA_TITLE_1;
import static android.support.mediacompat.testlib.MediaSessionConstants.TEST_MEDIA_TITLE_2;
import static android.support.mediacompat.testlib.MediaSessionConstants.TEST_QUEUE_ID_1;
import static android.support.mediacompat.testlib.MediaSessionConstants.TEST_SESSION_TAG;
import static android.support.mediacompat.testlib.MediaSessionConstants.TEST_VALUE;
import static android.support.mediacompat.testlib.VersionConstants.KEY_CLIENT_VERSION;
import static android.support.mediacompat.testlib.VersionConstants.VERSION_TOT;
import static android.support.mediacompat.testlib.util.IntentUtil.callMediaControllerMethod;
import static android.support.mediacompat.testlib.util.IntentUtil.callTransportControlsMethod;
import static android.support.mediacompat.testlib.util.TestUtil.assertBundleEquals;
import static android.support.v4.media.session.MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS;
import static android.support.v4.media.session.MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS;
import static androidx.media.MediaSessionManager.RemoteUserInfo.LEGACY_CONTROLLER;
import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
import static androidx.test.platform.app.InstrumentationRegistry.getArguments;
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import android.app.PendingIntent;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.media.AudioManager;
import android.media.session.MediaController;
import android.media.session.MediaSession;
import android.media.session.PlaybackState;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Parcel;
import android.os.Process;
import android.os.ResultReceiver;
import android.os.SystemClock;
import android.support.mediacompat.testlib.util.IntentUtil;
import android.support.mediacompat.testlib.util.PollingCheck;
import android.support.v4.media.MediaBrowserCompat;
import android.support.v4.media.MediaDescriptionCompat;
import android.support.v4.media.RatingCompat;
import android.support.v4.media.session.MediaControllerCompat;
import android.support.v4.media.session.MediaSessionCompat;
import android.support.v4.media.session.PlaybackStateCompat;
import android.text.TextUtils;
import android.util.Log;
import android.view.KeyEvent;
import androidx.media.MediaSessionManager.RemoteUserInfo;
import androidx.media.VolumeProviderCompat;
import androidx.media.test.lib.CustomParcelable;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.FlakyTest;
import androidx.test.filters.MediumTest;
import androidx.test.filters.SdkSuppress;
import androidx.test.filters.SmallTest;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
/**
* Test {@link MediaSessionCompat.Callback}.
*/
@RunWith(AndroidJUnit4.class)
public class MediaSessionCompatCallbackTest {
private static final String TAG = "MediaSessionCompatCallbackTest";
// The maximum time to wait for an operation.
private static final long TIME_OUT_MS = 3000L;
private static final long WAIT_TIME_FOR_NO_RESPONSE_MS = 300L;
private static final long TEST_POSITION = 1000000L;
private static final float TEST_PLAYBACK_SPEED = 3.0f;
private static final float DELTA = 1e-4f;
private static final boolean ENABLED = true;
private final Object mWaitLock = new Object();
private final Handler mHandler = new Handler(Looper.getMainLooper());
private String mClientVersion;
private MediaSessionCompat mSession;
private MediaSessionCallback mCallback = new MediaSessionCallback();
private AudioManager mAudioManager;
@Before
public void setUp() throws Exception {
// The version of the client app is provided through the instrumentation arguments.
mClientVersion = getArguments().getString(KEY_CLIENT_VERSION, "");
Log.d(TAG, "Client app version: " + mClientVersion);
getInstrumentation().runOnMainSync(new Runnable() {
@Override
public void run() {
mAudioManager = (AudioManager) getApplicationContext().getSystemService(
Context.AUDIO_SERVICE);
mSession = new MediaSessionCompat(getApplicationContext(), TEST_SESSION_TAG);
mSession.setCallback(mCallback, mHandler);
}
});
}
@After
public void tearDown() throws Exception {
mSession.release();
}
/**
* Tests that a session can be created and that all the fields are initialized correctly.
*/
@Test
@SmallTest
public void testCreateSession() throws Exception {
assertNotNull(mSession.getSessionToken());
assertFalse("New session should not be active", mSession.isActive());
// Verify by getting the controller and checking all its fields
MediaControllerCompat controller = mSession.getController();
assertNotNull(controller);
final String errorMsg = "New session has unexpected configuration.";
assertEquals(errorMsg, FLAG_HANDLES_MEDIA_BUTTONS | FLAG_HANDLES_TRANSPORT_CONTROLS,
controller.getFlags());
assertNull(errorMsg, controller.getExtras());
assertNull(errorMsg, controller.getMetadata());
assertEquals(errorMsg, getApplicationContext().getPackageName(),
controller.getPackageName());
assertNull(errorMsg, controller.getPlaybackState());
assertNull(errorMsg, controller.getQueue());
assertNull(errorMsg, controller.getQueueTitle());
assertEquals(errorMsg, RatingCompat.RATING_NONE, controller.getRatingType());
assertNull(errorMsg, controller.getSessionActivity());
assertNotNull(controller.getSessionToken());
assertNotNull(controller.getTransportControls());
MediaControllerCompat.PlaybackInfo info = controller.getPlaybackInfo();
assertNotNull(info);
assertEquals(errorMsg, MediaControllerCompat.PlaybackInfo.PLAYBACK_TYPE_LOCAL,
info.getPlaybackType());
assertEquals(errorMsg, mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC),
info.getCurrentVolume());
}
@Test
@SmallTest
public void testGetSessionToken() throws Exception {
assertEquals(mSession.getSessionToken(), mSession.getController().getSessionToken());
}
/**
* Tests that a session can be created from the framework session object and the callback
* set on the framework session object before fromSession() is called works properly.
*/
@Test
@SmallTest
public void testFromSession() throws Exception {
if (android.os.Build.VERSION.SDK_INT < 21) {
// MediaSession was introduced from API level 21.
return;
}
mCallback.reset(1);
mCallback.setExpectedCallerPackageName(getExpectedPackageNameForSelf());
mSession.setCallback(mCallback, new Handler(Looper.getMainLooper()));
MediaSessionCompat session = MediaSessionCompat.fromMediaSession(
getApplicationContext(), mSession.getMediaSession());
assertEquals(session.getSessionToken(), mSession.getSessionToken());
session.getController().getTransportControls().play();
mCallback.await(TIME_OUT_MS);
assertEquals(1, mCallback.mOnPlayCalledCount);
}
@Test
@SmallTest
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.LOLLIPOP)
public void testCallers() throws Exception {
mCallback.reset(1, getExpectedPackageNameForSelf());
mSession.setCallback(mCallback, new Handler(Looper.getMainLooper()));
MediaSessionCompat session = MediaSessionCompat.fromMediaSession(
getApplicationContext(), mSession.getMediaSession());
assertEquals(session.getSessionToken(), mSession.getSessionToken());
MediaControllerCompat controller1 = session.getController();
MediaControllerCompat controller2 =
new MediaControllerCompat(getApplicationContext(), session.getSessionToken());
controller1.getTransportControls().stop();
mCallback.await(TIME_OUT_MS);
assertTrue(mCallback.mOnStopCalled);
RemoteUserInfo remoteUserInfo1 = mCallback.mRemoteUserInfoForStop;
assertEquals(getExpectedPackageNameForSelf(), remoteUserInfo1.getPackageName());
if (Build.VERSION.SDK_INT >= 28) {
assertEquals(Process.myUid(), remoteUserInfo1.getUid());
assertEquals(Process.myPid(), remoteUserInfo1.getPid());
}
mCallback.reset(1, getExpectedPackageNameForSelf());
controller2.getTransportControls().stop();
mCallback.await(TIME_OUT_MS);
assertTrue(mCallback.mOnStopCalled);
RemoteUserInfo remoteUserInfo2 = mCallback.mRemoteUserInfoForStop;
assertEquals(getExpectedPackageNameForSelf(), remoteUserInfo2.getPackageName());
if (Build.VERSION.SDK_INT >= 28) {
assertEquals(Process.myUid(), remoteUserInfo2.getUid());
assertEquals(Process.myPid(), remoteUserInfo2.getPid());
}
}
/**
* Tests {@link MediaSessionCompat.Token} created in the constructor of MediaSessionCompat.
*/
@Test
@SmallTest
public void testSessionToken() throws Exception {
MediaSessionCompat.Token sessionToken = mSession.getSessionToken();
assertNotNull(sessionToken);
assertEquals(0, sessionToken.describeContents());
// Test writeToParcel
Parcel p = Parcel.obtain();
sessionToken.writeToParcel(p, 0);
p.setDataPosition(0);
MediaSessionCompat.Token token = MediaSessionCompat.Token.CREATOR.createFromParcel(p);
assertEquals(token, sessionToken);
p.recycle();
}
/**
* Tests {@link MediaSessionCompat.QueueItem}.
*/
@Test
@SmallTest
public void testQueueItem() {
MediaSessionCompat.QueueItem item = new MediaSessionCompat.QueueItem(
new MediaDescriptionCompat.Builder()
.setMediaId(TEST_MEDIA_ID_1)
.setTitle(TEST_MEDIA_TITLE_1)
.build(),
TEST_QUEUE_ID_1);
assertEquals(TEST_QUEUE_ID_1, item.getQueueId());
assertEquals(TEST_MEDIA_ID_1, item.getDescription().getMediaId());
assertEquals(TEST_MEDIA_TITLE_1, item.getDescription().getTitle());
assertEquals(0, item.describeContents());
Parcel p = Parcel.obtain();
item.writeToParcel(p, 0);
p.setDataPosition(0);
MediaSessionCompat.QueueItem other =
MediaSessionCompat.QueueItem.CREATOR.createFromParcel(p);
assertEquals(item.toString(), other.toString());
p.recycle();
}
/**
* Tests {@link MediaSessionCompat#setActive}.
*/
@Test
@SmallTest
public void testSetActive() throws Exception {
mSession.setActive(true);
assertTrue(mSession.isActive());
}
@Test
@SmallTest
public void testGetPlaybackStateWithPositionUpdate() throws InterruptedException {
final long stateSetTime = SystemClock.elapsedRealtime();
PlaybackStateCompat stateIn = new PlaybackStateCompat.Builder()
.setState(PlaybackStateCompat.STATE_PLAYING, TEST_POSITION, TEST_PLAYBACK_SPEED,
stateSetTime)
.build();
mSession.setPlaybackState(stateIn);
final long waitDuration = 100L;
Thread.sleep(waitDuration);
final long expectedUpdateTime = waitDuration + stateSetTime;
final long expectedPosition = (long) (TEST_PLAYBACK_SPEED * waitDuration) + TEST_POSITION;
final double updateTimeTolerance = 50L;
final double positionTolerance = updateTimeTolerance * TEST_PLAYBACK_SPEED;
PlaybackStateCompat stateOut = mSession.getController().getPlaybackState();
assertEquals(expectedUpdateTime, stateOut.getLastPositionUpdateTime(), updateTimeTolerance);
assertEquals(expectedPosition, stateOut.getPosition(), positionTolerance);
// Compare the result with MediaController.getPlaybackState().
if (Build.VERSION.SDK_INT >= 21) {
MediaController controller = new MediaController(
getApplicationContext(),
(MediaSession.Token) mSession.getSessionToken().getToken());
PlaybackState state = controller.getPlaybackState();
assertEquals(state.getLastPositionUpdateTime(), stateOut.getLastPositionUpdateTime(),
updateTimeTolerance);
assertEquals(state.getPosition(), stateOut.getPosition(), positionTolerance);
}
}
/**
* Tests {@link MediaSessionCompat#setCallback} with {@code null}.
* No callback messages should be posted once {@code setCallback(null)} is done.
*/
@Test
@SmallTest
public void testSetCallbackWithNull() throws Exception {
mSession.setActive(true);
mCallback.reset(1);
mSession.setCallback(null);
callTransportControlsMethod(PLAY, null, getApplicationContext(),
mSession.getSessionToken());
assertFalse(mCallback.await(WAIT_TIME_FOR_NO_RESPONSE_MS));
assertEquals("Callback shouldn't be called.", 0, mCallback.mOnPlayCalledCount);
}
/**
* Tests {@link MediaSessionCompat#setCallback} with {@code null}.
* From API 28, {@code setCallback(null)} should remove all posted callback messages.
* Therefore, no callback should be called once {@code setCallback(null)} is done.
*/
@Test
@SmallTest
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.P)
public void testSetCallbackWithNullShouldRemoveCallbackMessages() throws Exception {
mSession.setActive(true);
mCallback.reset(1);
getInstrumentation().runOnMainSync(new Runnable() {
@Override
public void run() {
callTransportControlsMethod(PLAY, null, getApplicationContext(),
mSession.getSessionToken());
mSession.setCallback(null);
}
});
assertFalse(mCallback.await(WAIT_TIME_FOR_NO_RESPONSE_MS));
assertEquals("Callback shouldn't be called.", 0, mCallback.mOnPlayCalledCount);
}
@Test
@SmallTest
public void testSendCommand() throws Exception {
mCallback.reset(1);
Bundle arguments = new Bundle();
arguments.putString("command", TEST_COMMAND);
Bundle extras = new Bundle();
extras.putString(TEST_KEY, TEST_VALUE);
arguments.putBundle("extras", extras);
ResultReceiver receiver = new ResultReceiver(null /* handler */);
arguments.putParcelable("resultReceiver", receiver);
callMediaControllerMethod(
SEND_COMMAND, arguments, getApplicationContext(), mSession.getSessionToken());
mCallback.await(TIME_OUT_MS);
assertTrue(mCallback.mOnCommandCalled);
assertNotNull(mCallback.mResultReceiver);
assertEquals(TEST_COMMAND, mCallback.mCommand);
assertBundleEquals(extras, mCallback.mExtras);
}
@Test
@SmallTest
public void testSendCommandWithNullResultReceiver() throws Exception {
mCallback.reset(1);
if (Build.VERSION.SDK_INT < 21 && !TextUtils.equals(VERSION_TOT, mClientVersion)) {
// In previous version, MediaControllerCompat#sendCommand() cannot send/receive a
// null ResultReceiver.
return;
}
Bundle arguments = new Bundle();
arguments.putString("command", TEST_COMMAND);
// No result receiver.
callMediaControllerMethod(
SEND_COMMAND, arguments, getApplicationContext(), mSession.getSessionToken());
mCallback.await(TIME_OUT_MS);
assertTrue(mCallback.mOnCommandCalled);
assertNull(mCallback.mResultReceiver);
assertEquals(TEST_COMMAND, mCallback.mCommand);
}
@Test
@SmallTest
public void testAddRemoveQueueItems() throws Exception {
mSession.setFlags(MediaSessionCompat.FLAG_HANDLES_QUEUE_COMMANDS);
MediaDescriptionCompat itemDescription1 = new MediaDescriptionCompat.Builder()
.setMediaId(TEST_MEDIA_ID_1).setTitle(TEST_MEDIA_TITLE_1).build();
MediaDescriptionCompat itemDescription2 = new MediaDescriptionCompat.Builder()
.setMediaId(TEST_MEDIA_ID_2).setTitle(TEST_MEDIA_TITLE_2).build();
mCallback.reset(1);
callMediaControllerMethod(
ADD_QUEUE_ITEM, itemDescription1, getApplicationContext(),
mSession.getSessionToken());
mCallback.await(TIME_OUT_MS);
assertTrue(mCallback.mOnAddQueueItemCalled);
assertEquals(-1, mCallback.mQueueIndex);
assertEquals(TEST_MEDIA_ID_1, mCallback.mQueueDescription.getMediaId());
assertEquals(TEST_MEDIA_TITLE_1, mCallback.mQueueDescription.getTitle());
mCallback.reset(1);
Bundle arguments = new Bundle();
arguments.putParcelable("description", itemDescription2);
arguments.putInt("index", 0);
callMediaControllerMethod(
ADD_QUEUE_ITEM_WITH_INDEX, arguments, getApplicationContext(),
mSession.getSessionToken());
mCallback.await(TIME_OUT_MS);
assertTrue(mCallback.mOnAddQueueItemAtCalled);
assertEquals(0, mCallback.mQueueIndex);
assertEquals(TEST_MEDIA_ID_2, mCallback.mQueueDescription.getMediaId());
assertEquals(TEST_MEDIA_TITLE_2, mCallback.mQueueDescription.getTitle());
mCallback.reset(1);
callMediaControllerMethod(
REMOVE_QUEUE_ITEM, itemDescription1, getApplicationContext(),
mSession.getSessionToken());
mCallback.await(TIME_OUT_MS);
assertTrue(mCallback.mOnRemoveQueueItemCalled);
assertEquals(TEST_MEDIA_ID_1, mCallback.mQueueDescription.getMediaId());
assertEquals(TEST_MEDIA_TITLE_1, mCallback.mQueueDescription.getTitle());
}
@Test
@SmallTest
public void testTransportControlsAndMediaSessionCallback() throws Exception {
mCallback.reset(1);
callTransportControlsMethod(PLAY, null, getApplicationContext(),
mSession.getSessionToken());
mCallback.await(TIME_OUT_MS);
assertEquals(1, mCallback.mOnPlayCalledCount);
mCallback.reset(1);
callTransportControlsMethod(PAUSE, null, getApplicationContext(),
mSession.getSessionToken());
mCallback.await(TIME_OUT_MS);
assertTrue(mCallback.mOnPauseCalled);
mCallback.reset(1);
callTransportControlsMethod(STOP, null, getApplicationContext(),
mSession.getSessionToken());
mCallback.await(TIME_OUT_MS);
assertTrue(mCallback.mOnStopCalled);
mCallback.reset(1);
callTransportControlsMethod(
FAST_FORWARD, null, getApplicationContext(), mSession.getSessionToken());
mCallback.await(TIME_OUT_MS);
assertTrue(mCallback.mOnFastForwardCalled);
mCallback.reset(1);
callTransportControlsMethod(REWIND, null, getApplicationContext(),
mSession.getSessionToken());
mCallback.await(TIME_OUT_MS);
assertTrue(mCallback.mOnRewindCalled);
mCallback.reset(1);
callTransportControlsMethod(
SKIP_TO_PREVIOUS, null, getApplicationContext(), mSession.getSessionToken());
mCallback.await(TIME_OUT_MS);
assertTrue(mCallback.mOnSkipToPreviousCalled);
mCallback.reset(1);
callTransportControlsMethod(
SKIP_TO_NEXT, null, getApplicationContext(), mSession.getSessionToken());
mCallback.await(TIME_OUT_MS);
assertTrue(mCallback.mOnSkipToNextCalled);
mCallback.reset(1);
final long seekPosition = 1000;
callTransportControlsMethod(
SEEK_TO, seekPosition, getApplicationContext(), mSession.getSessionToken());
mCallback.await(TIME_OUT_MS);
assertTrue(mCallback.mOnSeekToCalled);
assertEquals(seekPosition, mCallback.mSeekPosition);
mCallback.reset(1);
final RatingCompat rating =
RatingCompat.newStarRating(RatingCompat.RATING_5_STARS, 3f);
callTransportControlsMethod(
SET_RATING, rating, getApplicationContext(), mSession.getSessionToken());
mCallback.await(TIME_OUT_MS);
assertTrue(mCallback.mOnSetRatingCalled);
assertEquals(rating.getRatingStyle(), mCallback.mRating.getRatingStyle());
assertEquals(rating.getStarRating(), mCallback.mRating.getStarRating(), DELTA);
mCallback.reset(1);
final Bundle extras = new Bundle();
extras.putString(TEST_KEY, TEST_VALUE);
Bundle arguments = new Bundle();
arguments.putString("mediaId", TEST_MEDIA_ID_1);
arguments.putBundle("extras", extras);
callTransportControlsMethod(
PLAY_FROM_MEDIA_ID, arguments, getApplicationContext(), mSession.getSessionToken());
mCallback.await(TIME_OUT_MS);
assertTrue(mCallback.mOnPlayFromMediaIdCalled);
assertEquals(TEST_MEDIA_ID_1, mCallback.mMediaId);
assertBundleEquals(extras, mCallback.mExtras);
mCallback.reset(1);
final String query = "test-query";
arguments = new Bundle();
arguments.putString("query", query);
arguments.putBundle("extras", extras);
callTransportControlsMethod(
PLAY_FROM_SEARCH, arguments, getApplicationContext(), mSession.getSessionToken());
mCallback.await(TIME_OUT_MS);
assertTrue(mCallback.mOnPlayFromSearchCalled);
assertEquals(query, mCallback.mQuery);
assertBundleEquals(extras, mCallback.mExtras);
mCallback.reset(1);
final Uri uri = Uri.parse("content://test/popcorn.mod");
arguments = new Bundle();
arguments.putParcelable("uri", uri);
arguments.putBundle("extras", extras);
callTransportControlsMethod(
PLAY_FROM_URI, arguments, getApplicationContext(), mSession.getSessionToken());
mCallback.await(TIME_OUT_MS);
assertTrue(mCallback.mOnPlayFromUriCalled);
assertEquals(uri, mCallback.mUri);
assertBundleEquals(extras, mCallback.mExtras);
mCallback.reset(1);
final String action = "test-action";
arguments = new Bundle();
arguments.putString("action", action);
arguments.putBundle("extras", extras);
callTransportControlsMethod(
SEND_CUSTOM_ACTION, arguments, getApplicationContext(), mSession.getSessionToken());
mCallback.await(TIME_OUT_MS);
assertTrue(mCallback.mOnCustomActionCalled);
assertEquals(action, mCallback.mAction);
assertBundleEquals(extras, mCallback.mExtras);
mCallback.reset(1);
mCallback.mOnCustomActionCalled = false;
final PlaybackStateCompat.CustomAction customAction =
new PlaybackStateCompat.CustomAction.Builder(action, action, -1)
.setExtras(extras)
.build();
arguments = new Bundle();
arguments.putParcelable("action", customAction);
arguments.putBundle("extras", extras);
callTransportControlsMethod(
SEND_CUSTOM_ACTION_PARCELABLE,
arguments,
getApplicationContext(),
mSession.getSessionToken());
mCallback.await(TIME_OUT_MS);
assertTrue(mCallback.mOnCustomActionCalled);
assertEquals(action, mCallback.mAction);
assertBundleEquals(extras, mCallback.mExtras);
mCallback.reset(1);
final long queueItemId = 1000;
callTransportControlsMethod(
SKIP_TO_QUEUE_ITEM, queueItemId, getApplicationContext(),
mSession.getSessionToken());
mCallback.await(TIME_OUT_MS);
assertTrue(mCallback.mOnSkipToQueueItemCalled);
assertEquals(queueItemId, mCallback.mQueueItemId);
mCallback.reset(1);
callTransportControlsMethod(
PREPARE, null, getApplicationContext(), mSession.getSessionToken());
mCallback.await(TIME_OUT_MS);
assertTrue(mCallback.mOnPrepareCalled);
mCallback.reset(1);
arguments = new Bundle();
arguments.putString("mediaId", TEST_MEDIA_ID_2);
arguments.putBundle("extras", extras);
callTransportControlsMethod(
PREPARE_FROM_MEDIA_ID, arguments, getApplicationContext(),
mSession.getSessionToken());
mCallback.await(TIME_OUT_MS);
assertTrue(mCallback.mOnPrepareFromMediaIdCalled);
assertEquals(TEST_MEDIA_ID_2, mCallback.mMediaId);
assertBundleEquals(extras, mCallback.mExtras);
mCallback.reset(1);
arguments = new Bundle();
arguments.putString("query", query);
arguments.putBundle("extras", extras);
callTransportControlsMethod(
PREPARE_FROM_SEARCH, arguments, getApplicationContext(),
mSession.getSessionToken());
mCallback.await(TIME_OUT_MS);
assertTrue(mCallback.mOnPrepareFromSearchCalled);
assertEquals(query, mCallback.mQuery);
assertBundleEquals(extras, mCallback.mExtras);
mCallback.reset(1);
arguments = new Bundle();
arguments.putParcelable("uri", uri);
arguments.putBundle("extras", extras);
callTransportControlsMethod(
PREPARE_FROM_URI, arguments, getApplicationContext(), mSession.getSessionToken());
mCallback.await(TIME_OUT_MS);
assertTrue(mCallback.mOnPrepareFromUriCalled);
assertEquals(uri, mCallback.mUri);
assertBundleEquals(extras, mCallback.mExtras);
mCallback.reset(1);
callTransportControlsMethod(
SET_CAPTIONING_ENABLED, ENABLED, getApplicationContext(),
mSession.getSessionToken());
mCallback.await(TIME_OUT_MS);
assertTrue(mCallback.mOnSetCaptioningEnabledCalled);
assertEquals(ENABLED, mCallback.mCaptioningEnabled);
mCallback.reset(1);
final int repeatMode = PlaybackStateCompat.REPEAT_MODE_ALL;
callTransportControlsMethod(
SET_REPEAT_MODE, repeatMode, getApplicationContext(), mSession.getSessionToken());
mCallback.await(TIME_OUT_MS);
assertTrue(mCallback.mOnSetRepeatModeCalled);
assertEquals(repeatMode, mCallback.mRepeatMode);
mCallback.reset(1);
final int shuffleMode = PlaybackStateCompat.SHUFFLE_MODE_ALL;
callTransportControlsMethod(
SET_SHUFFLE_MODE, shuffleMode, getApplicationContext(), mSession.getSessionToken());
mCallback.await(TIME_OUT_MS);
assertTrue(mCallback.mOnSetShuffleModeCalled);
assertEquals(shuffleMode, mCallback.mShuffleMode);
}
/**
* Tests {@link MediaSessionCompat.Callback#onSetPlaybackSpeed(float)}.
*/
@Test
@SmallTest
public void testCallback_onSetPlaybackSpeed() {
if (!TextUtils.equals(VERSION_TOT, mClientVersion)) {
// In previous versions, MediaControllerCompat#setPlaybackSpeed() does not exist.
return;
}
mCallback.reset(1);
final float testSpeed = 2.0f;
callTransportControlsMethod(
SET_PLAYBACK_SPEED, testSpeed, getApplicationContext(), mSession.getSessionToken());
assertTrue(mCallback.await(TIME_OUT_MS));
assertTrue(mCallback.mOnSetPlaybackSpeedCalled);
assertEquals(testSpeed, mCallback.mSpeed, 0.0f);
}
/**
* Tests {@link MediaSessionCompat.Callback#onMediaButtonEvent}.
*/
@Test
@MediumTest
@FlakyTest(bugId = 111811728)
public void testCallbackOnMediaButtonEvent() throws Exception {
mSession.setActive(true);
final long waitTimeForNoResponse = 100L;
Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON)
.setComponent(new ComponentName(getApplicationContext(),
getApplicationContext().getClass()));
PendingIntent pi = PendingIntent.getBroadcast(getApplicationContext(), 0, mediaButtonIntent,
0);
mSession.setMediaButtonReceiver(pi);
// Set state to STATE_PLAYING to get higher priority.
setPlaybackState(PlaybackStateCompat.STATE_PLAYING);
mCallback.reset(1);
sendMediaKeyEventFromController(KeyEvent.KEYCODE_MEDIA_PLAY);
assertTrue(mCallback.await(TIME_OUT_MS));
assertEquals(1, mCallback.mOnPlayCalledCount);
mCallback.reset(1);
sendMediaKeyEventFromController(KeyEvent.KEYCODE_MEDIA_PAUSE);
assertTrue(mCallback.await(TIME_OUT_MS));
assertTrue(mCallback.mOnPauseCalled);
mCallback.reset(1);
sendMediaKeyEventFromController(KeyEvent.KEYCODE_MEDIA_NEXT);
assertTrue(mCallback.await(TIME_OUT_MS));
assertTrue(mCallback.mOnSkipToNextCalled);
mCallback.reset(1);
sendMediaKeyEventFromController(KeyEvent.KEYCODE_MEDIA_PREVIOUS);
assertTrue(mCallback.await(TIME_OUT_MS));
assertTrue(mCallback.mOnSkipToPreviousCalled);
mCallback.reset(1);
sendMediaKeyEventFromController(KeyEvent.KEYCODE_MEDIA_STOP);
assertTrue(mCallback.await(TIME_OUT_MS));
assertTrue(mCallback.mOnStopCalled);
mCallback.reset(1);
sendMediaKeyEventFromController(KeyEvent.KEYCODE_MEDIA_FAST_FORWARD);
assertTrue(mCallback.await(TIME_OUT_MS));
assertTrue(mCallback.mOnFastForwardCalled);
mCallback.reset(1);
sendMediaKeyEventFromController(KeyEvent.KEYCODE_MEDIA_REWIND);
assertTrue(mCallback.await(TIME_OUT_MS));
assertTrue(mCallback.mOnRewindCalled);
// Test PLAY_PAUSE button twice.
// First, send PLAY_PAUSE button event while in STATE_PAUSED.
mCallback.reset(1);
setPlaybackState(PlaybackStateCompat.STATE_PAUSED);
sendMediaKeyEventFromController(KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE);
assertTrue(mCallback.await(TIME_OUT_MS));
assertEquals(1, mCallback.mOnPlayCalledCount);
// Next, send PLAY_PAUSE button event while in STATE_PLAYING.
mCallback.reset(1);
setPlaybackState(PlaybackStateCompat.STATE_PLAYING);
sendMediaKeyEventFromController(KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE);
assertTrue(mCallback.await(TIME_OUT_MS));
assertTrue(mCallback.mOnPauseCalled);
// Double tap of PLAY_PAUSE is the next track.
mCallback.reset(2);
setPlaybackState(PlaybackStateCompat.STATE_PAUSED);
sendMediaKeyEventFromController(KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE);
sendMediaKeyEventFromController(KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE);
assertFalse(mCallback.await(waitTimeForNoResponse));
assertTrue(mCallback.mOnSkipToNextCalled);
assertEquals(0, mCallback.mOnPlayCalledCount);
assertFalse(mCallback.mOnPauseCalled);
// Test PLAY_PAUSE button long-press.
// It should be the same as the single short-press.
mCallback.reset(1);
setPlaybackState(PlaybackStateCompat.STATE_PAUSED);
sendMediaKeyEventFromController(KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE, true);
assertTrue(mCallback.await(TIME_OUT_MS));
assertEquals(1, mCallback.mOnPlayCalledCount);
// Double tap of PLAY_PAUSE should be handled once.
// Initial down event from the second press within double tap time-out will make
// onSkipToNext() to be called, so further down events shouldn't be handled again.
mCallback.reset(2);
sendMediaKeyEventFromController(KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE);
sendMediaKeyEventFromController(KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE, true);
assertFalse(mCallback.await(waitTimeForNoResponse));
assertTrue(mCallback.mOnSkipToNextCalled);
assertEquals(0, mCallback.mOnPlayCalledCount);
assertFalse(mCallback.mOnPauseCalled);
// Test PLAY_PAUSE button long-press followed by the short-press.
// Initial long-press of the PLAY_PAUSE is considered as the single short-press already,
// so it shouldn't be used as the first tap of the double tap.
mCallback.reset(2);
setPlaybackState(PlaybackStateCompat.STATE_PAUSED);
sendMediaKeyEventFromController(KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE, true);
sendMediaKeyEventFromController(KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE);
assertTrue(mCallback.await(TIME_OUT_MS));
// onMediaButtonEvent() calls either onPlay() or onPause() depending on the playback state,
// so onPlay() should be called once and onPause() also should be called once.
assertEquals(1, mCallback.mOnPlayCalledCount);
assertTrue(mCallback.mOnPauseCalled);
assertFalse(mCallback.mOnSkipToNextCalled);
// If another media key is pressed while the double tap of PLAY_PAUSE,
// PLAY_PAUSE should be handled as normal.
mCallback.reset(3);
setPlaybackState(PlaybackStateCompat.STATE_PAUSED);
sendMediaKeyEventFromController(KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE);
sendMediaKeyEventFromController(KeyEvent.KEYCODE_MEDIA_STOP);
sendMediaKeyEventFromController(KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE);
assertTrue(mCallback.await(TIME_OUT_MS));
assertFalse(mCallback.mOnSkipToNextCalled);
assertTrue(mCallback.mOnStopCalled);
assertEquals(2, mCallback.mOnPlayCalledCount);
// Test if media keys are handled in order.
mCallback.reset(2);
setPlaybackState(PlaybackStateCompat.STATE_PAUSED);
sendMediaKeyEventFromController(KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE);
sendMediaKeyEventFromController(KeyEvent.KEYCODE_MEDIA_STOP);
assertTrue(mCallback.await(TIME_OUT_MS));
assertEquals(1, mCallback.mOnPlayCalledCount);
assertTrue(mCallback.mOnStopCalled);
synchronized (mWaitLock) {
assertEquals(PlaybackStateCompat.STATE_STOPPED,
mSession.getController().getPlaybackState().getState());
}
}
@Test
@SmallTest
public void testSetVolumeWithLocalVolume() throws Exception {
if (Build.VERSION.SDK_INT >= 21 && mAudioManager.isVolumeFixed()) {
// This test is not eligible for this device.
return;
}
// Here, we intentionally choose STREAM_ALARM in order not to consider
// 'Do Not Disturb' or 'Volume limit'.
final int stream = AudioManager.STREAM_ALARM;
final int maxVolume = mAudioManager.getStreamMaxVolume(stream);
final int minVolume =
Build.VERSION.SDK_INT >= 28 ? mAudioManager.getStreamMinVolume(stream) : 0;
Log.d(TAG, "maxVolume=" + maxVolume + ", minVolume=" + minVolume);
if (maxVolume <= minVolume) {
return;
}
mSession.setPlaybackToLocal(stream);
final int originalVolume = mAudioManager.getStreamVolume(stream);
final int targetVolume = originalVolume == minVolume
? originalVolume + 1 : originalVolume - 1;
Log.d(TAG, "originalVolume=" + originalVolume + ", targetVolume=" + targetVolume);
callMediaControllerMethod(SET_VOLUME_TO, targetVolume, getApplicationContext(),
mSession.getSessionToken());
new PollingCheck(TIME_OUT_MS) {
@Override
protected boolean check() {
return targetVolume == mAudioManager.getStreamVolume(stream);
}
}.run();
// Set back to original volume.
mAudioManager.setStreamVolume(stream, originalVolume, 0 /* flags */);
}
@Test
@SmallTest
public void testAdjustVolumeWithLocalVolume() throws Exception {
if (Build.VERSION.SDK_INT >= 21 && mAudioManager.isVolumeFixed()) {
// This test is not eligible for this device.
return;
}
// Here, we intentionally choose STREAM_ALARM in order not to consider
// 'Do Not Disturb' or 'Volume limit'.
final int stream = AudioManager.STREAM_ALARM;
final int maxVolume = mAudioManager.getStreamMaxVolume(stream);
final int minVolume =
Build.VERSION.SDK_INT >= 28 ? mAudioManager.getStreamMinVolume(stream) : 0;
Log.d(TAG, "maxVolume=" + maxVolume + ", minVolume=" + minVolume);
if (maxVolume <= minVolume) {
return;
}
mSession.setPlaybackToLocal(stream);
final int originalVolume = mAudioManager.getStreamVolume(stream);
final int direction = originalVolume == minVolume
? AudioManager.ADJUST_RAISE : AudioManager.ADJUST_LOWER;
final int targetVolume = originalVolume + direction;
Log.d(TAG, "originalVolume=" + originalVolume + ", targetVolume=" + targetVolume);
callMediaControllerMethod(ADJUST_VOLUME, direction, getApplicationContext(),
mSession.getSessionToken());
new PollingCheck(TIME_OUT_MS) {
@Override
protected boolean check() {
return targetVolume == mAudioManager.getStreamVolume(stream);
}
}.run();
// Set back to original volume.
mAudioManager.setStreamVolume(stream, originalVolume, 0 /* flags */);
}
@Test
@SmallTest
public void testRemoteVolumeControl() throws Exception {
if (android.os.Build.VERSION.SDK_INT < 27) {
// This test causes an Exception on System UI in API < 27.
return;
}
VolumeProviderCompat vp =
new VolumeProviderCompat(VolumeProviderCompat.VOLUME_CONTROL_ABSOLUTE, 11, 5) {
@Override
public void onSetVolumeTo(int volume) {
synchronized (mWaitLock) {
setCurrentVolume(volume);
mWaitLock.notify();
}
}
@Override
public void onAdjustVolume(int direction) {
synchronized (mWaitLock) {
switch (direction) {
case AudioManager.ADJUST_LOWER:
setCurrentVolume(getCurrentVolume() - 1);
break;
case AudioManager.ADJUST_RAISE:
setCurrentVolume(getCurrentVolume() + 1);
break;
}
mWaitLock.notify();
}
}
};
mSession.setPlaybackToRemote(vp);
synchronized (mWaitLock) {
// test setVolumeTo
callMediaControllerMethod(SET_VOLUME_TO,
7 /* Target volume */, getApplicationContext(), mSession.getSessionToken());
mWaitLock.wait(TIME_OUT_MS);
assertEquals(7, vp.getCurrentVolume());
// test adjustVolume
callMediaControllerMethod(ADJUST_VOLUME,
AudioManager.ADJUST_LOWER, getApplicationContext(), mSession.getSessionToken());
mWaitLock.wait(TIME_OUT_MS);
assertEquals(6, vp.getCurrentVolume());
callMediaControllerMethod(ADJUST_VOLUME,
AudioManager.ADJUST_RAISE, getApplicationContext(), mSession.getSessionToken());
mWaitLock.wait(TIME_OUT_MS);
assertEquals(7, vp.getCurrentVolume());
}
}
@Test
@SmallTest
public void testReceivingMediaParcelables() throws Exception {
mCallback.reset(1);
final String action = "test-action";
Bundle arguments = new Bundle();
arguments.putString("action", action);
final MediaDescriptionCompat desc = new MediaDescriptionCompat.Builder()
.setMediaId("testMediaId")
.build();
final MediaSessionCompat.QueueItem queueItem =
new MediaSessionCompat.QueueItem(desc, 1 /* flags */);
final MediaBrowserCompat.MediaItem mediaItem =
new MediaBrowserCompat.MediaItem(desc, MediaBrowserCompat.MediaItem.FLAG_PLAYABLE);
final PlaybackStateCompat state = new PlaybackStateCompat.Builder()
.setBufferedPosition(1000)
.build();
Bundle extras = new Bundle();
extras.putParcelable("description", desc);
extras.putParcelable("queueItem", queueItem);
extras.putParcelable("mediaItem", mediaItem);
extras.putParcelable("state", state);
arguments.putBundle("extras", extras);
callTransportControlsMethod(
SEND_CUSTOM_ACTION, arguments, getApplicationContext(), mSession.getSessionToken());
mCallback.await(TIME_OUT_MS);
assertTrue(mCallback.mOnCustomActionCalled);
assertEquals(action, mCallback.mAction);
// Viewing the contents of bundle from remote process should not throw any exceptions.
// Also check whether the bundle has expected contents.
Bundle extrasOut = mCallback.mExtras;
assertNotNull(extrasOut);
assertNotNull(extrasOut.getClassLoader());
MediaDescriptionCompat descOut = extrasOut.getParcelable("description");
assertEquals(desc.getMediaId(), descOut.getMediaId());
MediaSessionCompat.QueueItem queueItemOut = extrasOut.getParcelable("queueItem");
assertEquals(queueItem.getQueueId(), queueItemOut.getQueueId());
MediaBrowserCompat.MediaItem mediaItemOut = extrasOut.getParcelable("mediaItem");
assertEquals(mediaItem.getFlags(), mediaItemOut.getFlags());
PlaybackStateCompat stateOut = extrasOut.getParcelable("state");
assertEquals(state.getBufferedPosition(), stateOut.getBufferedPosition());
}
@Test
@SmallTest
public void testMediaDescriptionContainsUserParcelable() {
mCallback.reset(1);
mSession.setFlags(MediaSessionCompat.FLAG_HANDLES_QUEUE_COMMANDS);
final int testValue = 3;
// The client app will call addQueueItem() with MediaDescriptionCompat which includes
// CustomParcelable created with given testValue.
callMediaControllerMethod(ADD_QUEUE_ITEM_WITH_CUSTOM_PARCELABLE,
testValue, getApplicationContext(), mSession.getSessionToken());
mCallback.await(TIME_OUT_MS);
assertTrue(mCallback.mOnAddQueueItemCalled);
CustomParcelable customParcelableOut =
mCallback.mQueueDescription.getExtras().getParcelable("customParcelable");
assertEquals(testValue, customParcelableOut.mValue);
}
private void setPlaybackState(int state) {
final long allActions = PlaybackStateCompat.ACTION_PLAY | PlaybackStateCompat.ACTION_PAUSE
| PlaybackStateCompat.ACTION_PLAY_PAUSE | PlaybackStateCompat.ACTION_STOP
| PlaybackStateCompat.ACTION_SKIP_TO_NEXT
| PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS
| PlaybackStateCompat.ACTION_FAST_FORWARD | PlaybackStateCompat.ACTION_REWIND;
PlaybackStateCompat playbackState = new PlaybackStateCompat.Builder().setActions(allActions)
.setState(state, 0L, 0.0f).build();
synchronized (mWaitLock) {
mSession.setPlaybackState(playbackState);
}
}
private void sendMediaKeyEventFromController(int keyCode) {
sendMediaKeyEventFromController(keyCode, false);
}
private void sendMediaKeyEventFromController(int keyCode, boolean isLongPress) {
long currentTimeMs = System.currentTimeMillis();
KeyEvent down = new KeyEvent(
currentTimeMs, currentTimeMs, KeyEvent.ACTION_DOWN, keyCode, 0);
callMediaControllerMethod(
DISPATCH_MEDIA_BUTTON, down, getApplicationContext(), mSession.getSessionToken());
if (isLongPress) {
KeyEvent longPress = new KeyEvent(
currentTimeMs, System.currentTimeMillis(), KeyEvent.ACTION_DOWN, keyCode, 1);
callMediaControllerMethod(
DISPATCH_MEDIA_BUTTON, longPress, getApplicationContext(),
mSession.getSessionToken());
}
KeyEvent up = new KeyEvent(
currentTimeMs, System.currentTimeMillis(), KeyEvent.ACTION_UP, keyCode, 0);
callMediaControllerMethod(
DISPATCH_MEDIA_BUTTON, up, getApplicationContext(), mSession.getSessionToken());
}
private String getExpectedPackageNameForSelf() {
if (Build.VERSION.SDK_INT >= 24 || Build.VERSION.SDK_INT < 21) {
return IntentUtil.SERVICE_PACKAGE_NAME;
} else {
return LEGACY_CONTROLLER;
}
}
private class MediaSessionCallback extends MediaSessionCompat.Callback {
private CountDownLatch mLatch;
private RemoteUserInfo mRemoteUserInfoForStop;
private String mExpectedCallerPackageName;
private long mSeekPosition;
private long mQueueItemId;
private RatingCompat mRating;
private String mMediaId;
private String mQuery;
private Uri mUri;
private String mAction;
private String mCommand;
private Bundle mExtras;
private ResultReceiver mResultReceiver;
private boolean mCaptioningEnabled;
private int mRepeatMode;
private int mShuffleMode;
private int mQueueIndex;
private MediaDescriptionCompat mQueueDescription;
private List<MediaSessionCompat.QueueItem> mQueue = new ArrayList<>();
private float mSpeed;
private int mOnPlayCalledCount;
private boolean mOnPauseCalled;
private boolean mOnStopCalled;
private boolean mOnFastForwardCalled;
private boolean mOnRewindCalled;
private boolean mOnSkipToPreviousCalled;
private boolean mOnSkipToNextCalled;
private boolean mOnSeekToCalled;
private boolean mOnSkipToQueueItemCalled;
private boolean mOnSetRatingCalled;
private boolean mOnPlayFromMediaIdCalled;
private boolean mOnPlayFromSearchCalled;
private boolean mOnPlayFromUriCalled;
private boolean mOnCustomActionCalled;
private boolean mOnCommandCalled;
private boolean mOnPrepareCalled;
private boolean mOnPrepareFromMediaIdCalled;
private boolean mOnPrepareFromSearchCalled;
private boolean mOnPrepareFromUriCalled;
private boolean mOnSetCaptioningEnabledCalled;
private boolean mOnSetRepeatModeCalled;
private boolean mOnSetShuffleModeCalled;
private boolean mOnAddQueueItemCalled;
private boolean mOnAddQueueItemAtCalled;
private boolean mOnRemoveQueueItemCalled;
private boolean mOnSetPlaybackSpeedCalled;
public void reset(int count) {
mLatch = new CountDownLatch(count);
if (Build.VERSION.SDK_INT >= 24 || Build.VERSION.SDK_INT < 21) {
setExpectedCallerPackageName(IntentUtil.CLIENT_PACKAGE_NAME);
} else {
setExpectedCallerPackageName(LEGACY_CONTROLLER);
}
mSeekPosition = -1;
mQueueItemId = -1;
mRating = null;
mMediaId = null;
mQuery = null;
mUri = null;
mAction = null;
mExtras = null;
mCommand = null;
mResultReceiver = null;
mCaptioningEnabled = false;
mRepeatMode = PlaybackStateCompat.REPEAT_MODE_NONE;
mShuffleMode = PlaybackStateCompat.SHUFFLE_MODE_NONE;
mQueueIndex = -1;
mQueueDescription = null;
mSpeed = -1.0f;
mRemoteUserInfoForStop = null;
mOnPlayCalledCount = 0;
mOnPauseCalled = false;
mOnStopCalled = false;
mOnFastForwardCalled = false;
mOnRewindCalled = false;
mOnSkipToPreviousCalled = false;
mOnSkipToNextCalled = false;
mOnSkipToQueueItemCalled = false;
mOnSeekToCalled = false;
mOnSetRatingCalled = false;
mOnPlayFromMediaIdCalled = false;
mOnPlayFromSearchCalled = false;
mOnPlayFromUriCalled = false;
mOnCustomActionCalled = false;
mOnCommandCalled = false;
mOnPrepareCalled = false;
mOnPrepareFromMediaIdCalled = false;
mOnPrepareFromSearchCalled = false;
mOnPrepareFromUriCalled = false;
mOnSetCaptioningEnabledCalled = false;
mOnSetRepeatModeCalled = false;
mOnSetShuffleModeCalled = false;
mOnAddQueueItemCalled = false;
mOnAddQueueItemAtCalled = false;
mOnRemoveQueueItemCalled = false;
mOnSetPlaybackSpeedCalled = false;
}
public void reset(int count, String expectedCallerPackageName) {
reset(count);
setExpectedCallerPackageName(expectedCallerPackageName);
}
public void setExpectedCallerPackageName(String packageName) {
mExpectedCallerPackageName = packageName;
}
public boolean await(long timeoutMs) {
try {
return mLatch.await(timeoutMs, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
return false;
}
}
@Override
public void onPlay() {
if (!isCallerTestClient()) {
// Ignore
return;
}
mOnPlayCalledCount++;
setPlaybackState(PlaybackStateCompat.STATE_PLAYING);
mLatch.countDown();
}
@Override
public void onPause() {
if (!isCallerTestClient()) {
// Ignore
return;
}
mOnPauseCalled = true;
setPlaybackState(PlaybackStateCompat.STATE_PAUSED);
mLatch.countDown();
}
@Override
public void onStop() {
if (!isCallerTestClient()) {
// Ignore
return;
}
mOnStopCalled = true;
setPlaybackState(PlaybackStateCompat.STATE_STOPPED);
mRemoteUserInfoForStop = mSession.getCurrentControllerInfo();
mLatch.countDown();
}
@Override
public void onFastForward() {
if (!isCallerTestClient()) {
// Ignore
return;
}
mOnFastForwardCalled = true;
mLatch.countDown();
}
@Override
public void onRewind() {
if (!isCallerTestClient()) {
// Ignore
return;
}
mOnRewindCalled = true;
mLatch.countDown();
}
@Override
public void onSkipToPrevious() {
if (!isCallerTestClient()) {
// Ignore
return;
}
mOnSkipToPreviousCalled = true;
mLatch.countDown();
}
@Override
public void onSkipToNext() {
if (!isCallerTestClient()) {
// Ignore
return;
}
mOnSkipToNextCalled = true;
mLatch.countDown();
}
@Override
public void onSeekTo(long pos) {
if (!isCallerTestClient()) {
// Ignore
return;
}
mOnSeekToCalled = true;
mSeekPosition = pos;
mLatch.countDown();
}
@Override
public void onSetRating(RatingCompat rating) {
if (!isCallerTestClient()) {
// Ignore
return;
}
mOnSetRatingCalled = true;
mRating = rating;
mLatch.countDown();
}
@Override
public void onPlayFromMediaId(String mediaId, Bundle extras) {
if (!isCallerTestClient()) {
// Ignore
return;
}
mOnPlayFromMediaIdCalled = true;
mMediaId = mediaId;
mExtras = extras;
mLatch.countDown();
}
@Override
public void onPlayFromSearch(String query, Bundle extras) {
if (!isCallerTestClient()) {
// Ignore
return;
}
mOnPlayFromSearchCalled = true;
mQuery = query;
mExtras = extras;
mLatch.countDown();
}
@Override
public void onPlayFromUri(Uri uri, Bundle extras) {
if (!isCallerTestClient()) {
// Ignore
return;
}
mOnPlayFromUriCalled = true;
mUri = uri;
mExtras = extras;
mLatch.countDown();
}
@Override
public void onCustomAction(String action, Bundle extras) {
if (!isCallerTestClient()) {
// Ignore
return;
}
mOnCustomActionCalled = true;
mAction = action;
mExtras = extras;
mLatch.countDown();
}
@Override
public void onSkipToQueueItem(long id) {
if (!isCallerTestClient()) {
// Ignore
return;
}
mOnSkipToQueueItemCalled = true;
mQueueItemId = id;
mLatch.countDown();
}
@Override
public void onCommand(String command, Bundle extras, ResultReceiver cb) {
if (!isCallerTestClient()) {
// Ignore
return;
}
mOnCommandCalled = true;
mCommand = command;
mExtras = extras;
mResultReceiver = cb;
mLatch.countDown();
}
@Override
public void onPrepare() {
if (!isCallerTestClient()) {
// Ignore
return;
}
mOnPrepareCalled = true;
mLatch.countDown();
}
@Override
public void onPrepareFromMediaId(String mediaId, Bundle extras) {
if (!isCallerTestClient()) {
// Ignore
return;
}
mOnPrepareFromMediaIdCalled = true;
mMediaId = mediaId;
mExtras = extras;
mLatch.countDown();
}
@Override
public void onPrepareFromSearch(String query, Bundle extras) {
if (!isCallerTestClient()) {
// Ignore
return;
}
mOnPrepareFromSearchCalled = true;
mQuery = query;
mExtras = extras;
mLatch.countDown();
}
@Override
public void onPrepareFromUri(Uri uri, Bundle extras) {
if (!isCallerTestClient()) {
// Ignore
return;
}
mOnPrepareFromUriCalled = true;
mUri = uri;
mExtras = extras;
mLatch.countDown();
}
@Override
public void onSetRepeatMode(int repeatMode) {
if (!isCallerTestClient()) {
// Ignore
return;
}
mOnSetRepeatModeCalled = true;
mRepeatMode = repeatMode;
mLatch.countDown();
}
@Override
public void onAddQueueItem(MediaDescriptionCompat description) {
if (!isCallerTestClient()) {
// Ignore
return;
}
mOnAddQueueItemCalled = true;
mQueueDescription = description;
mQueue.add(new MediaSessionCompat.QueueItem(description, mQueue.size()));
mSession.setQueue(mQueue);
mLatch.countDown();
}
@Override
public void onAddQueueItem(MediaDescriptionCompat description, int index) {
if (!isCallerTestClient()) {
// Ignore
return;
}
mOnAddQueueItemAtCalled = true;
mQueueIndex = index;
mQueueDescription = description;
mQueue.add(index, new MediaSessionCompat.QueueItem(description, mQueue.size()));
mSession.setQueue(mQueue);
mLatch.countDown();
}
@Override
public void onRemoveQueueItem(MediaDescriptionCompat description) {
if (!isCallerTestClient()) {
// Ignore
return;
}
mOnRemoveQueueItemCalled = true;
String mediaId = description.getMediaId();
for (int i = mQueue.size() - 1; i >= 0; --i) {
if (mediaId.equals(mQueue.get(i).getDescription().getMediaId())) {
mQueueDescription = mQueue.remove(i).getDescription();
mSession.setQueue(mQueue);
break;
}
}
mLatch.countDown();
}
@Override
public void onSetCaptioningEnabled(boolean enabled) {
if (!isCallerTestClient()) {
// Ignore
return;
}
mOnSetCaptioningEnabledCalled = true;
mCaptioningEnabled = enabled;
mLatch.countDown();
}
@Override
public void onSetShuffleMode(int shuffleMode) {
if (!isCallerTestClient()) {
// Ignore
return;
}
mOnSetShuffleModeCalled = true;
mShuffleMode = shuffleMode;
mLatch.countDown();
}
@Override
public void onSetPlaybackSpeed(float speed) {
if (!isCallerTestClient()) {
// Ignore
return;
}
mOnSetPlaybackSpeedCalled = true;
mSpeed = speed;
mLatch.countDown();
}
private boolean isCallerTestClient() {
RemoteUserInfo info = mSession.getCurrentControllerInfo();
assertNotNull(info);
// Don't stop test for an unexpected package name here, because any controller may
// connect to test session and send command while testing.
return mExpectedCallerPackageName.equals(info.getPackageName());
}
}
}