Add seekPrev and seekNext buttons on the default compact notification
This change is for Android 12 and below, where the buttons are derived from the actions added with the notification. From Android 13 (https://developer.android.com/about/versions/13/behavior-changes-13#playback-controls), the system derives media controls from `PlaybackState` actions. When adding the actions onto the notification, the logic will iterate all the command buttons. The `COMMAND_KEY_CONPACT_VIEW_INDEX` extra will be checked for each button. If that extra is set for the three buttons on the compact view, then the customized buttons and their order will be used. Otherwise, the compact view will be "seekPrev" (if any), "play/pause" (if any), "seekNext" (if any) buttons (in such order). Issue: androidx/media#410 PiperOrigin-RevId: 538797874
This commit is contained in:
parent
a7cff4e0e3
commit
2e2f19351f
@ -58,6 +58,9 @@
|
|||||||
allow requested `MediaItems` to be passed onto `Player` if they have
|
allow requested `MediaItems` to be passed onto `Player` if they have
|
||||||
`LocalConfiguration` (e.g. URI)
|
`LocalConfiguration` (e.g. URI)
|
||||||
([#282](https://github.com/androidx/media/issues/282)).
|
([#282](https://github.com/androidx/media/issues/282)).
|
||||||
|
* Add "seek to previous" and "seek to next" command buttons on compact
|
||||||
|
media notification view by default for Android 12 and below
|
||||||
|
([#410](https://github.com/androidx/media/issues/410)).
|
||||||
* UI:
|
* UI:
|
||||||
* Downloads:
|
* Downloads:
|
||||||
* OkHttp Extension:
|
* OkHttp Extension:
|
||||||
|
@ -401,9 +401,10 @@ public class DefaultMediaNotificationProvider implements MediaNotification.Provi
|
|||||||
* <p>Override this method to customize the buttons on the notification. Commands of the buttons
|
* <p>Override this method to customize the buttons on the notification. Commands of the buttons
|
||||||
* returned by this method must be contained in {@link MediaController#getAvailableCommands()}.
|
* returned by this method must be contained in {@link MediaController#getAvailableCommands()}.
|
||||||
*
|
*
|
||||||
* <p>By default, the notification shows {@link Player#COMMAND_PLAY_PAUSE} in {@linkplain
|
* <p>By default, the notification shows buttons for {@link Player#seekToPreviousMediaItem()},
|
||||||
* Notification.MediaStyle#setShowActionsInCompactView(int...) compact view}. This can be
|
* {@link Player#play()} or {@link Player#pause()}, {@link Player#seekToNextMediaItem()} in
|
||||||
* customized by defining the index of the command in compact view of up to 3 commands in their
|
* {@linkplain Notification.MediaStyle#setShowActionsInCompactView(int...) compact view}. This can
|
||||||
|
* be customized by defining the index of the command in compact view of up to 3 commands in their
|
||||||
* extras with key {@link DefaultMediaNotificationProvider#COMMAND_KEY_COMPACT_VIEW_INDEX}.
|
* extras with key {@link DefaultMediaNotificationProvider#COMMAND_KEY_COMPACT_VIEW_INDEX}.
|
||||||
*
|
*
|
||||||
* <p>To make the custom layout and commands work, you need to {@linkplain
|
* <p>To make the custom layout and commands work, you need to {@linkplain
|
||||||
@ -491,9 +492,11 @@ public class DefaultMediaNotificationProvider implements MediaNotification.Provi
|
|||||||
* and define which actions are shown in compact view by returning the indices of the buttons to
|
* and define which actions are shown in compact view by returning the indices of the buttons to
|
||||||
* be shown in compact view.
|
* be shown in compact view.
|
||||||
*
|
*
|
||||||
* <p>By default, {@link Player#COMMAND_PLAY_PAUSE} is shown in compact view, unless some of the
|
* <p>By default, the buttons for {@link Player#seekToPreviousMediaItem()}, {@link Player#play()}
|
||||||
* buttons are marked with {@link DefaultMediaNotificationProvider#COMMAND_KEY_COMPACT_VIEW_INDEX}
|
* or {@link Player#pause()}, {@link Player#seekToNextMediaItem()} are shown in compact view,
|
||||||
* to declare the index in compact view of the given command button in the button extras.
|
* unless some of the buttons are marked with {@link
|
||||||
|
* DefaultMediaNotificationProvider#COMMAND_KEY_COMPACT_VIEW_INDEX} to declare the index in
|
||||||
|
* compact view of the given command button in the button extras.
|
||||||
*
|
*
|
||||||
* @param mediaSession The media session to which the actions will be sent.
|
* @param mediaSession The media session to which the actions will be sent.
|
||||||
* @param mediaButtons The command buttons to be included in the notification.
|
* @param mediaButtons The command buttons to be included in the notification.
|
||||||
@ -509,7 +512,9 @@ public class DefaultMediaNotificationProvider implements MediaNotification.Provi
|
|||||||
NotificationCompat.Builder builder,
|
NotificationCompat.Builder builder,
|
||||||
MediaNotification.ActionFactory actionFactory) {
|
MediaNotification.ActionFactory actionFactory) {
|
||||||
int[] compactViewIndices = new int[3];
|
int[] compactViewIndices = new int[3];
|
||||||
|
int[] defaultCompactViewIndices = new int[3];
|
||||||
Arrays.fill(compactViewIndices, INDEX_UNSET);
|
Arrays.fill(compactViewIndices, INDEX_UNSET);
|
||||||
|
Arrays.fill(defaultCompactViewIndices, INDEX_UNSET);
|
||||||
int compactViewCommandCount = 0;
|
int compactViewCommandCount = 0;
|
||||||
for (int i = 0; i < mediaButtons.size(); i++) {
|
for (int i = 0; i < mediaButtons.size(); i++) {
|
||||||
CommandButton commandButton = mediaButtons.get(i);
|
CommandButton commandButton = mediaButtons.get(i);
|
||||||
@ -534,10 +539,26 @@ public class DefaultMediaNotificationProvider implements MediaNotification.Provi
|
|||||||
if (compactViewIndex >= 0 && compactViewIndex < compactViewIndices.length) {
|
if (compactViewIndex >= 0 && compactViewIndex < compactViewIndices.length) {
|
||||||
compactViewCommandCount++;
|
compactViewCommandCount++;
|
||||||
compactViewIndices[compactViewIndex] = i;
|
compactViewIndices[compactViewIndex] = i;
|
||||||
} else if (commandButton.playerCommand == COMMAND_PLAY_PAUSE
|
} else if (commandButton.playerCommand == COMMAND_SEEK_TO_PREVIOUS
|
||||||
&& compactViewCommandCount == 0) {
|
|| commandButton.playerCommand == COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM) {
|
||||||
// If there is no custom configuration we use the play/pause action in compact view.
|
defaultCompactViewIndices[0] = i;
|
||||||
compactViewIndices[0] = i;
|
} else if (commandButton.playerCommand == COMMAND_PLAY_PAUSE) {
|
||||||
|
defaultCompactViewIndices[1] = i;
|
||||||
|
} else if (commandButton.playerCommand == COMMAND_SEEK_TO_NEXT
|
||||||
|
|| commandButton.playerCommand == COMMAND_SEEK_TO_NEXT_MEDIA_ITEM) {
|
||||||
|
defaultCompactViewIndices[2] = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (compactViewCommandCount == 0) {
|
||||||
|
// If there is no custom configuration we use the seekPrev (if any), play/pause (if any),
|
||||||
|
// seekNext (if any) action in compact view.
|
||||||
|
int indexInCompactViewIndices = 0;
|
||||||
|
for (int i = 0; i < defaultCompactViewIndices.length; i++) {
|
||||||
|
if (defaultCompactViewIndices[i] == INDEX_UNSET) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
compactViewIndices[indexInCompactViewIndices] = defaultCompactViewIndices[i];
|
||||||
|
indexInCompactViewIndices++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (int i = 0; i < compactViewIndices.length; i++) {
|
for (int i = 0; i < compactViewIndices.length; i++) {
|
||||||
|
@ -20,15 +20,16 @@ import static androidx.media3.session.DefaultMediaNotificationProvider.DEFAULT_C
|
|||||||
import static androidx.media3.session.DefaultMediaNotificationProvider.DEFAULT_NOTIFICATION_ID;
|
import static androidx.media3.session.DefaultMediaNotificationProvider.DEFAULT_NOTIFICATION_ID;
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
|
import static org.mockito.ArgumentMatchers.anyInt;
|
||||||
import static org.mockito.ArgumentMatchers.eq;
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.times;
|
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
import static org.mockito.Mockito.verifyNoInteractions;
|
import static org.mockito.Mockito.verifyNoInteractions;
|
||||||
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
import static org.robolectric.Shadows.shadowOf;
|
import static org.robolectric.Shadows.shadowOf;
|
||||||
|
|
||||||
|
import android.app.Notification;
|
||||||
import android.app.NotificationChannel;
|
import android.app.NotificationChannel;
|
||||||
import android.app.NotificationManager;
|
import android.app.NotificationManager;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
@ -49,10 +50,11 @@ import androidx.test.ext.junit.runners.AndroidJUnit4;
|
|||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
import com.google.common.util.concurrent.SettableFuture;
|
import com.google.common.util.concurrent.SettableFuture;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.mockito.ArgumentCaptor;
|
|
||||||
import org.mockito.InOrder;
|
import org.mockito.InOrder;
|
||||||
|
import org.mockito.Mock;
|
||||||
import org.mockito.Mockito;
|
import org.mockito.Mockito;
|
||||||
import org.robolectric.Robolectric;
|
import org.robolectric.Robolectric;
|
||||||
import org.robolectric.Shadows;
|
import org.robolectric.Shadows;
|
||||||
@ -64,6 +66,39 @@ import org.robolectric.shadows.ShadowNotificationManager;
|
|||||||
public class DefaultMediaNotificationProviderTest {
|
public class DefaultMediaNotificationProviderTest {
|
||||||
|
|
||||||
private final Context context = ApplicationProvider.getApplicationContext();
|
private final Context context = ApplicationProvider.getApplicationContext();
|
||||||
|
private static final String TEST_CHANNEL_ID = "test_channel_id";
|
||||||
|
private static final NotificationCompat.Action fakeAction =
|
||||||
|
new NotificationCompat.Action(0, null, null);
|
||||||
|
/**
|
||||||
|
* The key string is defined as <a
|
||||||
|
* href=https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:core/core/src/main/java/androidx/core/app/NotificationCompatJellybean.java?q=EXTRA_ALLOW_GENERATED_REPLIES>
|
||||||
|
* {@code NotificationCompatJellybean.EXTRA_ALLOW_GENERATED_REPLIES}</a>
|
||||||
|
*/
|
||||||
|
private static final String EXTRA_ALLOW_GENERATED_REPLIES =
|
||||||
|
"android.support.allowGeneratedReplies";
|
||||||
|
/**
|
||||||
|
* The key string is defined as <a
|
||||||
|
* href=https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:core/core/src/main/java/androidx/core/app/NotificationCompat.java?q=EXTRA_SHOWS_USER_INTERFACE>
|
||||||
|
* {@code NotificationCompat.EXTRA_SHOWS_USER_INTERFACE}</a>
|
||||||
|
*/
|
||||||
|
private static final String EXTRA_SHOWS_USER_INTERFACE =
|
||||||
|
"android.support.action.showsUserInterface";
|
||||||
|
/**
|
||||||
|
* The key string is defined as <a
|
||||||
|
* href=https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:core/core/src/main/java/androidx/core/app/NotificationCompat.java?q=EXTRA_SEMANTIC_ACTION>
|
||||||
|
* {@code NotificationCompat.EXTRA_SEMANTIC_ACTION}</a>
|
||||||
|
*/
|
||||||
|
private static final String EXTRA_SEMANTIC_ACTION = "android.support.action.semanticAction";
|
||||||
|
|
||||||
|
@Mock private MediaNotification.ActionFactory mockActionFactory;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
mockActionFactory = mock(MediaNotification.ActionFactory.class);
|
||||||
|
when(mockActionFactory.createCustomActionFromCustomCommandButton(any(), any()))
|
||||||
|
.thenReturn(fakeAction);
|
||||||
|
when(mockActionFactory.createMediaAction(any(), any(), any(), anyInt())).thenReturn(fakeAction);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getMediaButtons_playWhenReadyTrueOrFalse_correctPlayPauseResources() {
|
public void getMediaButtons_playWhenReadyTrueOrFalse_correctPlayPauseResources() {
|
||||||
@ -167,8 +202,9 @@ public class DefaultMediaNotificationProviderTest {
|
|||||||
DefaultMediaNotificationProvider defaultMediaNotificationProvider =
|
DefaultMediaNotificationProvider defaultMediaNotificationProvider =
|
||||||
new DefaultMediaNotificationProvider.Builder(ApplicationProvider.getApplicationContext())
|
new DefaultMediaNotificationProvider.Builder(ApplicationProvider.getApplicationContext())
|
||||||
.build();
|
.build();
|
||||||
NotificationCompat.Builder mockNotificationBuilder = mock(NotificationCompat.Builder.class);
|
NotificationCompat.Builder notificationBuilder =
|
||||||
MediaNotification.ActionFactory mockActionFactory = mock(MediaNotification.ActionFactory.class);
|
new NotificationCompat.Builder(
|
||||||
|
ApplicationProvider.getApplicationContext(), TEST_CHANNEL_ID);
|
||||||
CommandButton commandButton1 =
|
CommandButton commandButton1 =
|
||||||
new CommandButton.Builder()
|
new CommandButton.Builder()
|
||||||
.setPlayerCommand(Player.COMMAND_PLAY_PAUSE)
|
.setPlayerCommand(Player.COMMAND_PLAY_PAUSE)
|
||||||
@ -209,12 +245,12 @@ public class DefaultMediaNotificationProviderTest {
|
|||||||
defaultMediaNotificationProvider.addNotificationActions(
|
defaultMediaNotificationProvider.addNotificationActions(
|
||||||
mediaSession,
|
mediaSession,
|
||||||
ImmutableList.of(commandButton1, commandButton2, commandButton3, commandButton4),
|
ImmutableList.of(commandButton1, commandButton2, commandButton3, commandButton4),
|
||||||
mockNotificationBuilder,
|
notificationBuilder,
|
||||||
mockActionFactory);
|
mockActionFactory);
|
||||||
mediaSession.release();
|
mediaSession.release();
|
||||||
player.release();
|
player.release();
|
||||||
|
|
||||||
verify(mockNotificationBuilder, times(4)).addAction(any());
|
assertThat(notificationBuilder.build().actions).hasLength(4);
|
||||||
InOrder inOrder = Mockito.inOrder(mockActionFactory);
|
InOrder inOrder = Mockito.inOrder(mockActionFactory);
|
||||||
inOrder
|
inOrder
|
||||||
.verify(mockActionFactory)
|
.verify(mockActionFactory)
|
||||||
@ -234,12 +270,14 @@ public class DefaultMediaNotificationProviderTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void addNotificationActions_playPauseCommandNoCustomDeclaration_playPauseInCompactView() {
|
public void
|
||||||
|
addNotificationActions_playPauseSeekPrevSeekNextCommands_noCustomDeclaration_seekPrevPlayPauseSeekNextInCompactView() {
|
||||||
DefaultMediaNotificationProvider defaultMediaNotificationProvider =
|
DefaultMediaNotificationProvider defaultMediaNotificationProvider =
|
||||||
new DefaultMediaNotificationProvider.Builder(ApplicationProvider.getApplicationContext())
|
new DefaultMediaNotificationProvider.Builder(ApplicationProvider.getApplicationContext())
|
||||||
.build();
|
.build();
|
||||||
NotificationCompat.Builder mockNotificationBuilder = mock(NotificationCompat.Builder.class);
|
NotificationCompat.Builder notificationBuilder =
|
||||||
MediaNotification.ActionFactory mockActionFactory = mock(MediaNotification.ActionFactory.class);
|
new NotificationCompat.Builder(
|
||||||
|
ApplicationProvider.getApplicationContext(), TEST_CHANNEL_ID);
|
||||||
CommandButton commandButton1 =
|
CommandButton commandButton1 =
|
||||||
new CommandButton.Builder()
|
new CommandButton.Builder()
|
||||||
.setDisplayName("displayName")
|
.setDisplayName("displayName")
|
||||||
@ -252,23 +290,31 @@ public class DefaultMediaNotificationProviderTest {
|
|||||||
.setDisplayName("displayName")
|
.setDisplayName("displayName")
|
||||||
.setIconResId(R.drawable.media3_icon_circular_play)
|
.setIconResId(R.drawable.media3_icon_circular_play)
|
||||||
.build();
|
.build();
|
||||||
|
CommandButton commandButton3 =
|
||||||
|
new CommandButton.Builder()
|
||||||
|
.setPlayerCommand(Player.COMMAND_SEEK_TO_PREVIOUS)
|
||||||
|
.setDisplayName("displayName")
|
||||||
|
.setIconResId(R.drawable.media3_icon_circular_play)
|
||||||
|
.build();
|
||||||
|
CommandButton commandButton4 =
|
||||||
|
new CommandButton.Builder()
|
||||||
|
.setPlayerCommand(Player.COMMAND_SEEK_TO_NEXT)
|
||||||
|
.setDisplayName("displayName")
|
||||||
|
.setIconResId(R.drawable.media3_icon_circular_play)
|
||||||
|
.build();
|
||||||
Player player = new TestExoPlayerBuilder(context).build();
|
Player player = new TestExoPlayerBuilder(context).build();
|
||||||
MediaSession mediaSession = new MediaSession.Builder(context, player).build();
|
MediaSession mediaSession = new MediaSession.Builder(context, player).build();
|
||||||
|
|
||||||
int[] compactViewIndices =
|
int[] compactViewIndices =
|
||||||
defaultMediaNotificationProvider.addNotificationActions(
|
defaultMediaNotificationProvider.addNotificationActions(
|
||||||
mediaSession,
|
mediaSession,
|
||||||
ImmutableList.of(commandButton1, commandButton2),
|
ImmutableList.of(commandButton1, commandButton2, commandButton3, commandButton4),
|
||||||
mockNotificationBuilder,
|
notificationBuilder,
|
||||||
mockActionFactory);
|
mockActionFactory);
|
||||||
mediaSession.release();
|
mediaSession.release();
|
||||||
player.release();
|
player.release();
|
||||||
|
|
||||||
ArgumentCaptor<NotificationCompat.Action> actionCaptor =
|
assertThat(notificationBuilder.build().actions).hasLength(4);
|
||||||
ArgumentCaptor.forClass(NotificationCompat.Action.class);
|
|
||||||
verify(mockNotificationBuilder, times(2)).addAction(actionCaptor.capture());
|
|
||||||
List<NotificationCompat.Action> actions = actionCaptor.getAllValues();
|
|
||||||
assertThat(actions).hasSize(2);
|
|
||||||
InOrder inOrder = Mockito.inOrder(mockActionFactory);
|
InOrder inOrder = Mockito.inOrder(mockActionFactory);
|
||||||
inOrder
|
inOrder
|
||||||
.verify(mockActionFactory)
|
.verify(mockActionFactory)
|
||||||
@ -277,18 +323,83 @@ public class DefaultMediaNotificationProviderTest {
|
|||||||
.verify(mockActionFactory)
|
.verify(mockActionFactory)
|
||||||
.createMediaAction(
|
.createMediaAction(
|
||||||
eq(mediaSession), any(), eq("displayName"), eq(commandButton2.playerCommand));
|
eq(mediaSession), any(), eq("displayName"), eq(commandButton2.playerCommand));
|
||||||
|
inOrder
|
||||||
|
.verify(mockActionFactory)
|
||||||
|
.createMediaAction(
|
||||||
|
eq(mediaSession), any(), eq("displayName"), eq(commandButton3.playerCommand));
|
||||||
|
inOrder
|
||||||
|
.verify(mockActionFactory)
|
||||||
|
.createMediaAction(
|
||||||
|
eq(mediaSession), any(), eq("displayName"), eq(commandButton4.playerCommand));
|
||||||
verifyNoMoreInteractions(mockActionFactory);
|
verifyNoMoreInteractions(mockActionFactory);
|
||||||
assertThat(compactViewIndices).asList().containsExactly(1);
|
assertThat(compactViewIndices).asList().containsExactly(2, 1, 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void
|
public void
|
||||||
addNotificationActions_noPlayPauseCommandNoCustomDeclaration_emptyCompactViewIndices() {
|
addNotificationActions_playPauseSeekPrevCommands_noCustomDeclaration_seekPrevPlayPauseInCompactView() {
|
||||||
DefaultMediaNotificationProvider defaultMediaNotificationProvider =
|
DefaultMediaNotificationProvider defaultMediaNotificationProvider =
|
||||||
new DefaultMediaNotificationProvider.Builder(ApplicationProvider.getApplicationContext())
|
new DefaultMediaNotificationProvider.Builder(ApplicationProvider.getApplicationContext())
|
||||||
.build();
|
.build();
|
||||||
NotificationCompat.Builder mockNotificationBuilder = mock(NotificationCompat.Builder.class);
|
NotificationCompat.Builder notificationBuilder =
|
||||||
MediaNotification.ActionFactory mockActionFactory = mock(MediaNotification.ActionFactory.class);
|
new NotificationCompat.Builder(
|
||||||
|
ApplicationProvider.getApplicationContext(), TEST_CHANNEL_ID);
|
||||||
|
CommandButton commandButton1 =
|
||||||
|
new CommandButton.Builder()
|
||||||
|
.setDisplayName("displayName")
|
||||||
|
.setIconResId(R.drawable.media3_icon_circular_play)
|
||||||
|
.setSessionCommand(new SessionCommand("action1", Bundle.EMPTY))
|
||||||
|
.build();
|
||||||
|
CommandButton commandButton2 =
|
||||||
|
new CommandButton.Builder()
|
||||||
|
.setPlayerCommand(Player.COMMAND_PLAY_PAUSE)
|
||||||
|
.setDisplayName("displayName")
|
||||||
|
.setIconResId(R.drawable.media3_icon_circular_play)
|
||||||
|
.build();
|
||||||
|
CommandButton commandButton3 =
|
||||||
|
new CommandButton.Builder()
|
||||||
|
.setPlayerCommand(Player.COMMAND_SEEK_TO_PREVIOUS)
|
||||||
|
.setDisplayName("displayName")
|
||||||
|
.setIconResId(R.drawable.media3_icon_circular_play)
|
||||||
|
.build();
|
||||||
|
Player player = new TestExoPlayerBuilder(context).build();
|
||||||
|
MediaSession mediaSession = new MediaSession.Builder(context, player).build();
|
||||||
|
|
||||||
|
int[] compactViewIndices =
|
||||||
|
defaultMediaNotificationProvider.addNotificationActions(
|
||||||
|
mediaSession,
|
||||||
|
ImmutableList.of(commandButton1, commandButton2, commandButton3),
|
||||||
|
notificationBuilder,
|
||||||
|
mockActionFactory);
|
||||||
|
mediaSession.release();
|
||||||
|
player.release();
|
||||||
|
|
||||||
|
assertThat(notificationBuilder.build().actions).hasLength(3);
|
||||||
|
InOrder inOrder = Mockito.inOrder(mockActionFactory);
|
||||||
|
inOrder
|
||||||
|
.verify(mockActionFactory)
|
||||||
|
.createCustomActionFromCustomCommandButton(mediaSession, commandButton1);
|
||||||
|
inOrder
|
||||||
|
.verify(mockActionFactory)
|
||||||
|
.createMediaAction(
|
||||||
|
eq(mediaSession), any(), eq("displayName"), eq(commandButton2.playerCommand));
|
||||||
|
inOrder
|
||||||
|
.verify(mockActionFactory)
|
||||||
|
.createMediaAction(
|
||||||
|
eq(mediaSession), any(), eq("displayName"), eq(commandButton3.playerCommand));
|
||||||
|
verifyNoMoreInteractions(mockActionFactory);
|
||||||
|
assertThat(compactViewIndices).asList().containsExactly(2, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void
|
||||||
|
addNotificationActions_noPlayPauseSeekPrevSeekNextCommands_noCustomDeclaration_emptyCompactViewIndices() {
|
||||||
|
DefaultMediaNotificationProvider defaultMediaNotificationProvider =
|
||||||
|
new DefaultMediaNotificationProvider.Builder(ApplicationProvider.getApplicationContext())
|
||||||
|
.build();
|
||||||
|
NotificationCompat.Builder notificationBuilder =
|
||||||
|
new NotificationCompat.Builder(
|
||||||
|
ApplicationProvider.getApplicationContext(), TEST_CHANNEL_ID);
|
||||||
CommandButton commandButton1 =
|
CommandButton commandButton1 =
|
||||||
new CommandButton.Builder()
|
new CommandButton.Builder()
|
||||||
.setDisplayName("displayName")
|
.setDisplayName("displayName")
|
||||||
@ -300,10 +411,7 @@ public class DefaultMediaNotificationProviderTest {
|
|||||||
|
|
||||||
int[] compactViewIndices =
|
int[] compactViewIndices =
|
||||||
defaultMediaNotificationProvider.addNotificationActions(
|
defaultMediaNotificationProvider.addNotificationActions(
|
||||||
mediaSession,
|
mediaSession, ImmutableList.of(commandButton1), notificationBuilder, mockActionFactory);
|
||||||
ImmutableList.of(commandButton1),
|
|
||||||
mockNotificationBuilder,
|
|
||||||
mockActionFactory);
|
|
||||||
mediaSession.release();
|
mediaSession.release();
|
||||||
player.release();
|
player.release();
|
||||||
|
|
||||||
@ -320,8 +428,9 @@ public class DefaultMediaNotificationProviderTest {
|
|||||||
DefaultMediaNotificationProvider defaultMediaNotificationProvider =
|
DefaultMediaNotificationProvider defaultMediaNotificationProvider =
|
||||||
new DefaultMediaNotificationProvider.Builder(ApplicationProvider.getApplicationContext())
|
new DefaultMediaNotificationProvider.Builder(ApplicationProvider.getApplicationContext())
|
||||||
.build();
|
.build();
|
||||||
NotificationCompat.Builder mockNotificationBuilder = mock(NotificationCompat.Builder.class);
|
NotificationCompat.Builder notificationBuilder =
|
||||||
MediaNotification.ActionFactory mockActionFactory = mock(MediaNotification.ActionFactory.class);
|
new NotificationCompat.Builder(
|
||||||
|
ApplicationProvider.getApplicationContext(), TEST_CHANNEL_ID);
|
||||||
Bundle commandButtonBundle1 = new Bundle();
|
Bundle commandButtonBundle1 = new Bundle();
|
||||||
commandButtonBundle1.putInt(DefaultMediaNotificationProvider.COMMAND_KEY_COMPACT_VIEW_INDEX, 2);
|
commandButtonBundle1.putInt(DefaultMediaNotificationProvider.COMMAND_KEY_COMPACT_VIEW_INDEX, 2);
|
||||||
CommandButton commandButton1 =
|
CommandButton commandButton1 =
|
||||||
@ -348,7 +457,7 @@ public class DefaultMediaNotificationProviderTest {
|
|||||||
defaultMediaNotificationProvider.addNotificationActions(
|
defaultMediaNotificationProvider.addNotificationActions(
|
||||||
mediaSession,
|
mediaSession,
|
||||||
ImmutableList.of(commandButton1, commandButton2),
|
ImmutableList.of(commandButton1, commandButton2),
|
||||||
mockNotificationBuilder,
|
notificationBuilder,
|
||||||
mockActionFactory);
|
mockActionFactory);
|
||||||
mediaSession.release();
|
mediaSession.release();
|
||||||
player.release();
|
player.release();
|
||||||
@ -369,8 +478,9 @@ public class DefaultMediaNotificationProviderTest {
|
|||||||
DefaultMediaNotificationProvider defaultMediaNotificationProvider =
|
DefaultMediaNotificationProvider defaultMediaNotificationProvider =
|
||||||
new DefaultMediaNotificationProvider.Builder(ApplicationProvider.getApplicationContext())
|
new DefaultMediaNotificationProvider.Builder(ApplicationProvider.getApplicationContext())
|
||||||
.build();
|
.build();
|
||||||
NotificationCompat.Builder mockNotificationBuilder = mock(NotificationCompat.Builder.class);
|
NotificationCompat.Builder notificationBuilder =
|
||||||
MediaNotification.ActionFactory mockActionFactory = mock(MediaNotification.ActionFactory.class);
|
new NotificationCompat.Builder(
|
||||||
|
ApplicationProvider.getApplicationContext(), TEST_CHANNEL_ID);
|
||||||
Bundle commandButtonBundle = new Bundle();
|
Bundle commandButtonBundle = new Bundle();
|
||||||
commandButtonBundle.putInt(DefaultMediaNotificationProvider.COMMAND_KEY_COMPACT_VIEW_INDEX, 1);
|
commandButtonBundle.putInt(DefaultMediaNotificationProvider.COMMAND_KEY_COMPACT_VIEW_INDEX, 1);
|
||||||
CommandButton commandButton1 =
|
CommandButton commandButton1 =
|
||||||
@ -385,10 +495,7 @@ public class DefaultMediaNotificationProviderTest {
|
|||||||
|
|
||||||
int[] compactViewIndices =
|
int[] compactViewIndices =
|
||||||
defaultMediaNotificationProvider.addNotificationActions(
|
defaultMediaNotificationProvider.addNotificationActions(
|
||||||
mediaSession,
|
mediaSession, ImmutableList.of(commandButton1), notificationBuilder, mockActionFactory);
|
||||||
ImmutableList.of(commandButton1),
|
|
||||||
mockNotificationBuilder,
|
|
||||||
mockActionFactory);
|
|
||||||
mediaSession.release();
|
mediaSession.release();
|
||||||
player.release();
|
player.release();
|
||||||
|
|
||||||
@ -406,7 +513,9 @@ public class DefaultMediaNotificationProviderTest {
|
|||||||
DefaultMediaNotificationProvider defaultMediaNotificationProvider =
|
DefaultMediaNotificationProvider defaultMediaNotificationProvider =
|
||||||
new DefaultMediaNotificationProvider.Builder(ApplicationProvider.getApplicationContext())
|
new DefaultMediaNotificationProvider.Builder(ApplicationProvider.getApplicationContext())
|
||||||
.build();
|
.build();
|
||||||
NotificationCompat.Builder mockNotificationBuilder = mock(NotificationCompat.Builder.class);
|
NotificationCompat.Builder notificationBuilder =
|
||||||
|
new NotificationCompat.Builder(
|
||||||
|
ApplicationProvider.getApplicationContext(), TEST_CHANNEL_ID);
|
||||||
DefaultActionFactory defaultActionFactory =
|
DefaultActionFactory defaultActionFactory =
|
||||||
new DefaultActionFactory(Robolectric.setupService(TestService.class));
|
new DefaultActionFactory(Robolectric.setupService(TestService.class));
|
||||||
Bundle commandButtonBundle = new Bundle();
|
Bundle commandButtonBundle = new Bundle();
|
||||||
@ -422,22 +531,20 @@ public class DefaultMediaNotificationProviderTest {
|
|||||||
MediaSession mediaSession = new MediaSession.Builder(context, player).build();
|
MediaSession mediaSession = new MediaSession.Builder(context, player).build();
|
||||||
|
|
||||||
defaultMediaNotificationProvider.addNotificationActions(
|
defaultMediaNotificationProvider.addNotificationActions(
|
||||||
mediaSession,
|
mediaSession, ImmutableList.of(commandButton1), notificationBuilder, defaultActionFactory);
|
||||||
ImmutableList.of(commandButton1),
|
|
||||||
mockNotificationBuilder,
|
|
||||||
defaultActionFactory);
|
|
||||||
mediaSession.release();
|
mediaSession.release();
|
||||||
player.release();
|
player.release();
|
||||||
|
|
||||||
ArgumentCaptor<NotificationCompat.Action> actionCaptor =
|
Notification.Action[] actions = notificationBuilder.build().actions;
|
||||||
ArgumentCaptor.forClass(NotificationCompat.Action.class);
|
assertThat(actions).hasLength(1);
|
||||||
verify(mockNotificationBuilder).addAction(actionCaptor.capture());
|
assertThat(String.valueOf(actions[0].title)).isEqualTo("displayName1");
|
||||||
verifyNoMoreInteractions(mockNotificationBuilder);
|
assertThat(actions[0].getIcon().getResId()).isEqualTo(commandButton1.iconResId);
|
||||||
List<NotificationCompat.Action> actions = actionCaptor.getAllValues();
|
Bundle extrasInAction = actions[0].getExtras();
|
||||||
assertThat(actions).hasSize(1);
|
// Remove platform extras added during the construction of Notification.Action.
|
||||||
assertThat(String.valueOf(actions.get(0).title)).isEqualTo("displayName1");
|
extrasInAction.remove(EXTRA_ALLOW_GENERATED_REPLIES);
|
||||||
assertThat(actions.get(0).getIconCompat().getResId()).isEqualTo(commandButton1.iconResId);
|
extrasInAction.remove(EXTRA_SHOWS_USER_INTERFACE);
|
||||||
assertThat(actions.get(0).getExtras().size()).isEqualTo(0);
|
extrasInAction.remove(EXTRA_SEMANTIC_ACTION);
|
||||||
|
assertThat(extrasInAction.size()).isEqualTo(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Loading…
x
Reference in New Issue
Block a user