Add missing tests for custom layout notification

PiperOrigin-RevId: 451859199
This commit is contained in:
bachinger 2022-05-30 12:47:58 +00:00 committed by Marc Baechinger
parent 7af9f02067
commit bf3d81c262
6 changed files with 296 additions and 50 deletions

View File

@ -23,6 +23,7 @@ public class MediaSessionConstants {
// Test method names
public static final String TEST_GET_SESSION_ACTIVITY = "testGetSessionActivity";
public static final String TEST_WITH_CUSTOM_COMMANDS = "testWithCustomCommands";
public static final String TEST_CONTROLLER_LISTENER_SESSION_REJECTS = "connection_sessionRejects";
public static final String TEST_IS_SESSION_COMMAND_AVAILABLE = "testIsSessionCommandAvailable";

View File

@ -0,0 +1,140 @@
/*
* Copyright 2022 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.media3.session;
import static androidx.media3.test.session.common.CommonConstants.DEFAULT_TEST_NAME;
import static com.google.common.truth.Truth.assertThat;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import android.content.Context;
import android.os.Bundle;
import android.os.RemoteException;
import android.support.v4.media.session.MediaControllerCompat;
import android.support.v4.media.session.MediaSessionCompat;
import android.support.v4.media.session.PlaybackStateCompat;
import androidx.media3.test.session.common.HandlerThreadTestRule;
import androidx.media3.test.session.common.MainLooperTestRule;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.LargeTest;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import org.junit.After;
import org.junit.Before;
import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.RuleChain;
import org.junit.rules.TestRule;
import org.junit.runner.RunWith;
/**
* Tests for {@link MediaControllerCompat.Callback} with {@link MediaSessionCompat}.
*
* <p>The tests in this class represents the reference specific usages of the legacy API for which
* we need to provide support with the Media3 API.
*
* <p>So these test are actually not tests but rather a reference of how the legacy API is used and
* expected to work.
*/
@RunWith(AndroidJUnit4.class)
@LargeTest
public class MediaControllerCompatCallbackWithMediaSessionCompatTest {
private static final int TIMEOUT_MS = 1_000;
@ClassRule public static MainLooperTestRule mainLooperTestRule = new MainLooperTestRule();
private final HandlerThreadTestRule threadTestRule =
new HandlerThreadTestRule("MediaControllerCompatCallbackWithMediaSessionCompatTest");
private final MediaControllerTestRule controllerTestRule =
new MediaControllerTestRule(threadTestRule);
@Rule
public final TestRule chain = RuleChain.outerRule(threadTestRule).around(controllerTestRule);
private Context context;
private RemoteMediaSessionCompat session;
@Before
public void setUp() throws Exception {
context = ApplicationProvider.getApplicationContext();
session = new RemoteMediaSessionCompat(DEFAULT_TEST_NAME, context);
}
@After
public void cleanUp() throws RemoteException {
session.cleanUp();
}
/** Custom actions in the legacy session used for instance by Android Auto and Wear OS. */
@Test
public void setPlaybackState_withCustomActions_onPlaybackStateCompatChangedCalled()
throws Exception {
MediaSessionCompat.Token sessionToken = session.getSessionToken();
Bundle extras1 = new Bundle();
extras1.putString("key", "value-1");
PlaybackStateCompat.CustomAction customAction1 =
new PlaybackStateCompat.CustomAction.Builder("action1", "actionName1", /* icon= */ 1)
.setExtras(extras1)
.build();
Bundle extras2 = new Bundle();
extras2.putString("key", "value-2");
PlaybackStateCompat.CustomAction customAction2 =
new PlaybackStateCompat.CustomAction.Builder("action2", "actionName2", /* icon= */ 2)
.setExtras(extras2)
.build();
PlaybackStateCompat.Builder builder =
new PlaybackStateCompat.Builder()
.addCustomAction(customAction1)
.addCustomAction(customAction2);
List<String> receivedActions = new ArrayList<>();
List<String> receivedDisplayNames = new ArrayList<>();
List<String> receivedBundleValues = new ArrayList<>();
List<Integer> receivedIconResIds = new ArrayList<>();
CountDownLatch countDownLatch = new CountDownLatch(1);
threadTestRule
.getHandler()
.postAndSync(
() -> {
MediaControllerCompat mediaControllerCompat =
new MediaControllerCompat(context, sessionToken);
mediaControllerCompat.registerCallback(
new MediaControllerCompat.Callback() {
@Override
public void onPlaybackStateChanged(PlaybackStateCompat state) {
List<PlaybackStateCompat.CustomAction> layout = state.getCustomActions();
for (PlaybackStateCompat.CustomAction action : layout) {
receivedActions.add(action.getAction());
receivedDisplayNames.add(String.valueOf(action.getName()));
receivedBundleValues.add(action.getExtras().getString("key"));
receivedIconResIds.add(action.getIcon());
}
countDownLatch.countDown();
}
});
});
session.setPlaybackState(builder.build());
assertThat(countDownLatch.await(TIMEOUT_MS, MILLISECONDS)).isTrue();
assertThat(receivedActions).containsExactly("action1", "action2").inOrder();
assertThat(receivedDisplayNames).containsExactly("actionName1", "actionName2").inOrder();
assertThat(receivedIconResIds).containsExactly(1, 2).inOrder();
assertThat(receivedBundleValues).containsExactly("value-1", "value-2").inOrder();
}
}

View File

@ -769,52 +769,54 @@ public class MediaControllerCompatCallbackWithMediaSessionTest {
}
@Test
public void customLayoutChanged_updatesPlaybackStateCompat() throws Exception {
AtomicReference<PlaybackStateCompat> playbackStateRef = new AtomicReference<>();
public void setCustomLayout_onPlaybackStateCompatChangedCalled() throws Exception {
List<CommandButton> buttons = new ArrayList<>();
Bundle extras1 = new Bundle();
extras1.putString("key", "value-1");
CommandButton button1 =
new CommandButton.Builder()
.setSessionCommand(new SessionCommand("action1", extras1))
.setDisplayName("actionName1")
.setIconResId(1)
.build();
Bundle extras2 = new Bundle();
extras2.putString("key", "value-2");
CommandButton button2 =
new CommandButton.Builder()
.setSessionCommand(new SessionCommand("action2", extras2))
.setDisplayName("actionName2")
.setIconResId(2)
.build();
buttons.add(button1);
buttons.add(button2);
List<String> receivedActions = new ArrayList<>();
List<String> receivedDisplayNames = new ArrayList<>();
List<String> receivedBundleValues = new ArrayList<>();
List<Integer> receivedIconResIds = new ArrayList<>();
CountDownLatch latch = new CountDownLatch(1);
MediaControllerCompat.Callback callback =
new MediaControllerCompat.Callback() {
@Override
public void onPlaybackStateChanged(PlaybackStateCompat state) {
playbackStateRef.set(state);
List<PlaybackStateCompat.CustomAction> layout = state.getCustomActions();
for (PlaybackStateCompat.CustomAction action : layout) {
receivedActions.add(action.getAction());
receivedDisplayNames.add(String.valueOf(action.getName()));
receivedBundleValues.add(action.getExtras().getString("key"));
receivedIconResIds.add(action.getIcon());
}
latch.countDown();
}
};
controllerCompat.registerCallback(callback, handler);
List<CommandButton> customLayout = new ArrayList<>();
Bundle customCommandBundle1 = new Bundle();
customCommandBundle1.putString("customKey1", "customValue1");
customLayout.add(
new CommandButton.Builder()
.setDisplayName("customCommandName1")
.setIconResId(1)
.setSessionCommand(new SessionCommand("customCommandAction1", customCommandBundle1))
.build());
Bundle customCommandBundle2 = new Bundle();
customCommandBundle2.putString("customKey2", "customValue2");
customLayout.add(
new CommandButton.Builder()
.setDisplayName("customCommandName2")
.setIconResId(2)
.setSessionCommand(new SessionCommand("customCommandAction2", customCommandBundle2))
.build());
session.setCustomLayout(customLayout);
session.setCustomLayout(buttons);
assertThat(latch.await(TIMEOUT_MS, MILLISECONDS)).isTrue();
List<PlaybackStateCompat.CustomAction> customActions =
playbackStateRef.get().getCustomActions();
assertThat(customActions).hasSize(2);
assertThat(customActions.get(0).getAction()).isEqualTo("customCommandAction1");
assertThat(customActions.get(0).getName()).isEqualTo("customCommandName1");
assertThat(customActions.get(0).getIcon()).isEqualTo(1);
assertThat(TestUtils.equals(customActions.get(0).getExtras(), customCommandBundle1)).isTrue();
assertThat(customActions.get(1).getAction()).isEqualTo("customCommandAction2");
assertThat(customActions.get(1).getName()).isEqualTo("customCommandName2");
assertThat(customActions.get(1).getIcon()).isEqualTo(2);
assertThat(TestUtils.equals(customActions.get(1).getExtras(), customCommandBundle2)).isTrue();
assertThat(receivedActions).containsExactly("action1", "action2").inOrder();
assertThat(receivedDisplayNames).containsExactly("actionName1", "actionName2").inOrder();
assertThat(receivedIconResIds).containsExactly(1, 2).inOrder();
assertThat(receivedBundleValues).containsExactly("value-1", "value-2").inOrder();
}
@Test

View File

@ -15,7 +15,6 @@
*/
package androidx.media3.session;
import static androidx.media3.common.Player.COMMAND_PLAY_PAUSE;
import static androidx.media3.common.Player.COMMAND_SET_REPEAT_MODE;
import static androidx.media3.common.Player.EVENT_REPEAT_MODE_CHANGED;
import static androidx.media3.common.Player.EVENT_SHUFFLE_MODE_ENABLED_CHANGED;
@ -30,6 +29,7 @@ import static androidx.media3.test.session.common.CommonConstants.DEFAULT_TEST_N
import static androidx.media3.test.session.common.CommonConstants.MOCK_MEDIA3_LIBRARY_SERVICE;
import static androidx.media3.test.session.common.CommonConstants.MOCK_MEDIA3_SESSION_SERVICE;
import static androidx.media3.test.session.common.MediaSessionConstants.TEST_CONTROLLER_LISTENER_SESSION_REJECTS;
import static androidx.media3.test.session.common.MediaSessionConstants.TEST_WITH_CUSTOM_COMMANDS;
import static androidx.media3.test.session.common.TestUtils.LONG_TIMEOUT_MS;
import static androidx.media3.test.session.common.TestUtils.NO_RESPONSE_TIMEOUT_MS;
import static androidx.media3.test.session.common.TestUtils.TIMEOUT_MS;
@ -1743,37 +1743,61 @@ public class MediaControllerListenerTest {
}
@Test
public void onCustomLayoutChanged() throws Exception {
public void setCustomLayout_onSetCustomLayoutCalled() throws Exception {
List<CommandButton> buttons = new ArrayList<>();
CommandButton button =
Bundle extras1 = new Bundle();
extras1.putString("key", "value-1");
CommandButton button1 =
new CommandButton.Builder()
.setPlayerCommand(COMMAND_PLAY_PAUSE)
.setDisplayName("button")
.setSessionCommand(new SessionCommand("action1", extras1))
.setDisplayName("actionName1")
.setIconResId(1)
.build();
buttons.add(button);
Bundle extras2 = new Bundle();
extras2.putString("key", "value-2");
CommandButton button2 =
new CommandButton.Builder()
.setSessionCommand(new SessionCommand("action2", extras2))
.setDisplayName("actionName2")
.setIconResId(2)
.build();
buttons.add(button1);
buttons.add(button2);
CountDownLatch latch = new CountDownLatch(1);
List<String> receivedActions = new ArrayList<>();
List<String> receivedDisplayNames = new ArrayList<>();
List<String> receivedBundleValues = new ArrayList<>();
List<Integer> receivedIconResIds = new ArrayList<>();
List<Integer> receivedCommandCodes = new ArrayList<>();
MediaController.Listener listener =
new MediaController.Listener() {
@Override
public ListenableFuture<SessionResult> onSetCustomLayout(
MediaController controller, List<CommandButton> layout) {
assertThat(layout).hasSize(buttons.size());
for (int i = 0; i < layout.size(); i++) {
assertThat(layout.get(i).playerCommand).isEqualTo(buttons.get(i).playerCommand);
assertThat(layout.get(i).displayName.toString())
.isEqualTo(buttons.get(i).displayName.toString());
for (CommandButton button : layout) {
receivedActions.add(button.sessionCommand.customAction);
receivedDisplayNames.add(String.valueOf(button.displayName));
receivedBundleValues.add(button.sessionCommand.customExtras.getString("key"));
receivedCommandCodes.add(button.sessionCommand.commandCode);
receivedIconResIds.add(button.iconResId);
}
latch.countDown();
return Futures.immediateFuture(new SessionResult(RESULT_SUCCESS));
}
};
controllerTestRule.createController(
remoteSession.getToken(), /* connectionHints= */ null, listener);
RemoteMediaSession session = createRemoteMediaSession(TEST_WITH_CUSTOM_COMMANDS);
controllerTestRule.createController(session.getToken(), /* connectionHints= */ null, listener);
session.setCustomLayout(buttons);
remoteSession.setCustomLayout(buttons);
assertThat(latch.await(TIMEOUT_MS, MILLISECONDS)).isTrue();
assertThat(receivedActions).containsExactly("action1", "action2").inOrder();
assertThat(receivedCommandCodes)
.containsExactly(SessionCommand.COMMAND_CODE_CUSTOM, SessionCommand.COMMAND_CODE_CUSTOM)
.inOrder();
assertThat(receivedDisplayNames).containsExactly("actionName1", "actionName2").inOrder();
assertThat(receivedIconResIds).containsExactly(1, 2).inOrder();
assertThat(receivedBundleValues).containsExactly("value-1", "value-2").inOrder();
}
@Test

View File

@ -16,12 +16,14 @@
package androidx.media3.session;
import static androidx.media3.common.Player.EVENT_REPEAT_MODE_CHANGED;
import static androidx.media3.session.SessionResult.RESULT_SUCCESS;
import static androidx.media3.test.session.common.CommonConstants.DEFAULT_TEST_NAME;
import static androidx.media3.test.session.common.TestUtils.TIMEOUT_MS;
import static com.google.common.truth.Truth.assertThat;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import android.content.Context;
import android.os.Bundle;
import android.os.RemoteException;
import android.support.v4.media.session.MediaSessionCompat;
import android.support.v4.media.session.PlaybackStateCompat;
@ -33,6 +35,10 @@ import androidx.media3.test.session.common.MainLooperTestRule;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.LargeTest;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicReference;
@ -108,4 +114,58 @@ public class MediaControllerListenerWithMediaSessionCompatTest {
assertThat(listenerEventCodes).containsExactly(EVENT_REPEAT_MODE_CHANGED, EVENT_ON_EVENTS);
assertThat(eventsRef.get()).isEqualTo(testEvents);
}
@Test
public void setPlaybackState_withCustomActions_onSetCustomLayoutCalled() throws Exception {
Bundle extras1 = new Bundle();
extras1.putString("key", "value-1");
PlaybackStateCompat.CustomAction customAction1 =
new PlaybackStateCompat.CustomAction.Builder("action1", "actionName1", /* icon= */ 1)
.setExtras(extras1)
.build();
Bundle extras2 = new Bundle();
extras2.putString("key", "value-2");
PlaybackStateCompat.CustomAction customAction2 =
new PlaybackStateCompat.CustomAction.Builder("action2", "actionName2", /* icon= */ 2)
.setExtras(extras2)
.build();
PlaybackStateCompat.Builder builder =
new PlaybackStateCompat.Builder()
.addCustomAction(customAction1)
.addCustomAction(customAction2);
List<String> receivedActions = new ArrayList<>();
List<String> receivedDisplayNames = new ArrayList<>();
List<String> receivedBundleValues = new ArrayList<>();
List<Integer> receivedIconResIds = new ArrayList<>();
List<Integer> receivedCommandCodes = new ArrayList<>();
CountDownLatch countDownLatch = new CountDownLatch(1);
controllerTestRule.createController(
session.getSessionToken(),
new MediaController.Listener() {
@Override
public ListenableFuture<SessionResult> onSetCustomLayout(
MediaController controller, List<CommandButton> layout) {
for (CommandButton button : layout) {
receivedActions.add(button.sessionCommand.customAction);
receivedDisplayNames.add(String.valueOf(button.displayName));
receivedBundleValues.add(button.sessionCommand.customExtras.getString("key"));
receivedCommandCodes.add(button.sessionCommand.commandCode);
receivedIconResIds.add(button.iconResId);
}
countDownLatch.countDown();
return Futures.immediateFuture(new SessionResult(RESULT_SUCCESS));
}
});
session.setPlaybackState(builder.build());
assertThat(countDownLatch.await(TIMEOUT_MS, MILLISECONDS)).isTrue();
assertThat(receivedActions).containsExactly("action1", "action2").inOrder();
assertThat(receivedCommandCodes)
.containsExactly(SessionCommand.COMMAND_CODE_CUSTOM, SessionCommand.COMMAND_CODE_CUSTOM)
.inOrder();
assertThat(receivedDisplayNames).containsExactly("actionName1", "actionName2").inOrder();
assertThat(receivedIconResIds).containsExactly(1, 2).inOrder();
assertThat(receivedBundleValues).containsExactly("value-1", "value-2").inOrder();
}
}

View File

@ -57,6 +57,7 @@ import static androidx.media3.test.session.common.MediaSessionConstants.KEY_AVAI
import static androidx.media3.test.session.common.MediaSessionConstants.TEST_CONTROLLER_LISTENER_SESSION_REJECTS;
import static androidx.media3.test.session.common.MediaSessionConstants.TEST_GET_SESSION_ACTIVITY;
import static androidx.media3.test.session.common.MediaSessionConstants.TEST_IS_SESSION_COMMAND_AVAILABLE;
import static androidx.media3.test.session.common.MediaSessionConstants.TEST_WITH_CUSTOM_COMMANDS;
import android.app.PendingIntent;
import android.app.Service;
@ -177,6 +178,24 @@ public class MediaSessionProviderService extends Service {
builder.setSessionActivity(pendingIntent);
break;
}
case TEST_WITH_CUSTOM_COMMANDS:
{
SessionCommands availableSessionCommands =
new SessionCommands.Builder()
.add(new SessionCommand("action1", Bundle.EMPTY))
.add(new SessionCommand("action2", Bundle.EMPTY))
.build();
builder.setCallback(
new MediaSession.Callback() {
@Override
public MediaSession.ConnectionResult onConnect(
MediaSession session, ControllerInfo controller) {
return MediaSession.ConnectionResult.accept(
availableSessionCommands, Player.Commands.EMPTY);
}
});
break;
}
case TEST_CONTROLLER_LISTENER_SESSION_REJECTS:
{
builder.setCallback(