Use Media 3 command constants instead of legacy constants

PiperOrigin-RevId: 446425897
This commit is contained in:
bachinger 2022-05-04 13:02:37 +01:00 committed by Ian Baker
parent 5e139780f6
commit 9ca0f7862a
4 changed files with 65 additions and 76 deletions

View File

@ -15,17 +15,32 @@
*/
package androidx.media3.session;
import static android.view.KeyEvent.KEYCODE_MEDIA_FAST_FORWARD;
import static android.view.KeyEvent.KEYCODE_MEDIA_NEXT;
import static android.view.KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE;
import static android.view.KeyEvent.KEYCODE_MEDIA_PREVIOUS;
import static android.view.KeyEvent.KEYCODE_MEDIA_REWIND;
import static android.view.KeyEvent.KEYCODE_MEDIA_STOP;
import static android.view.KeyEvent.KEYCODE_UNKNOWN;
import static androidx.media3.common.Player.COMMAND_PLAY_PAUSE;
import static androidx.media3.common.Player.COMMAND_SEEK_BACK;
import static androidx.media3.common.Player.COMMAND_SEEK_FORWARD;
import static androidx.media3.common.Player.COMMAND_SEEK_TO_NEXT;
import static androidx.media3.common.Player.COMMAND_SEEK_TO_NEXT_MEDIA_ITEM;
import static androidx.media3.common.Player.COMMAND_SEEK_TO_PREVIOUS;
import static androidx.media3.common.Player.COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM;
import android.app.PendingIntent;
import android.app.Service;
import android.content.ComponentName;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.media.session.PlaybackStateCompat;
import android.view.KeyEvent;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.core.app.NotificationCompat;
import androidx.core.graphics.drawable.IconCompat;
import androidx.media3.common.Player;
import androidx.media3.common.util.UnstableApi;
import androidx.media3.common.util.Util;
@ -41,13 +56,15 @@ import androidx.media3.common.util.Util;
private final Service service;
private int customActionPendingIntentRequestCode = 0;
public DefaultActionFactory(Service service) {
this.service = service;
}
@Override
public NotificationCompat.Action createMediaAction(
IconCompat icon, CharSequence title, @Command long command) {
IconCompat icon, CharSequence title, @Player.Command long command) {
return new NotificationCompat.Action(icon, title, createMediaActionPendingIntent(command));
}
@ -59,12 +76,12 @@ import androidx.media3.common.util.Util;
}
@Override
public PendingIntent createMediaActionPendingIntent(@Command long command) {
int keyCode = PlaybackStateCompat.toKeyCode(command);
public PendingIntent createMediaActionPendingIntent(@Player.Command long command) {
int keyCode = toKeyCode(command);
Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON);
intent.setComponent(new ComponentName(service, service.getClass()));
intent.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_DOWN, keyCode));
if (Util.SDK_INT >= 26 && command == COMMAND_PLAY) {
if (Util.SDK_INT >= 26 && command == COMMAND_PLAY_PAUSE) {
return Api26.createForegroundServicePendingIntent(service, keyCode, intent);
} else {
return PendingIntent.getService(
@ -75,6 +92,24 @@ import androidx.media3.common.util.Util;
}
}
private int toKeyCode(@Player.Command long action) {
if (action == COMMAND_SEEK_TO_NEXT_MEDIA_ITEM || action == COMMAND_SEEK_TO_NEXT) {
return KEYCODE_MEDIA_NEXT;
} else if (action == COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM
|| action == COMMAND_SEEK_TO_PREVIOUS) {
return KEYCODE_MEDIA_PREVIOUS;
} else if (action == Player.COMMAND_STOP) {
return KEYCODE_MEDIA_STOP;
} else if (action == COMMAND_SEEK_FORWARD) {
return KEYCODE_MEDIA_FAST_FORWARD;
} else if (action == COMMAND_SEEK_BACK) {
return KEYCODE_MEDIA_REWIND;
} else if (action == COMMAND_PLAY_PAUSE) {
return KEYCODE_MEDIA_PLAY_PAUSE;
}
return KEYCODE_UNKNOWN;
}
private PendingIntent createCustomActionPendingIntent(String action, Bundle extras) {
Intent intent = new Intent(ACTION_CUSTOM);
intent.setComponent(new ComponentName(service, service.getClass()));
@ -83,7 +118,7 @@ import androidx.media3.common.util.Util;
// Custom actions always start the service in the background.
return PendingIntent.getService(
service,
/* requestCode= */ KeyEvent.KEYCODE_UNKNOWN,
/* requestCode= */ ++customActionPendingIntentRequestCode,
intent,
Util.SDK_INT >= 23 ? PendingIntent.FLAG_IMMUTABLE : 0);
}

View File

@ -15,6 +15,12 @@
*/
package androidx.media3.session;
import static androidx.media3.common.Player.COMMAND_PLAY_PAUSE;
import static androidx.media3.common.Player.COMMAND_SEEK_TO_NEXT;
import static androidx.media3.common.Player.COMMAND_SEEK_TO_NEXT_MEDIA_ITEM;
import static androidx.media3.common.Player.COMMAND_SEEK_TO_PREVIOUS;
import static androidx.media3.common.Player.COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM;
import static androidx.media3.common.Player.COMMAND_STOP;
import static androidx.media3.common.util.Assertions.checkStateNotNull;
import static androidx.media3.common.util.Util.castNonNull;
@ -52,13 +58,9 @@ import java.util.concurrent.ExecutionException;
* The following actions are included in the provided notifications:
*
* <ul>
* <li>{@link MediaNotification.ActionFactory#COMMAND_PLAY} to start playback. Included when
* {@link MediaController#getPlayWhenReady()} returns {@code false}.
* <li>{@link MediaNotification.ActionFactory#COMMAND_PAUSE}, to pause playback. Included when
* ({@link MediaController#getPlayWhenReady()} returns {@code true}.
* <li>{@link MediaNotification.ActionFactory#COMMAND_SKIP_TO_PREVIOUS} to skip to the previous
* item.
* <li>{@link MediaNotification.ActionFactory#COMMAND_SKIP_TO_NEXT} to skip to the next item.
* <li>{@link MediaController#COMMAND_PLAY_PAUSE} to start or pause playback.
* <li>{@link MediaController#COMMAND_SEEK_TO_PREVIOUS} to seek to the previous item.
* <li>{@link MediaController#COMMAND_SEEK_TO_NEXT} to seek to the next item.
* </ul>
*
* <h2>Drawables</h2>
@ -120,17 +122,17 @@ public final class DefaultMediaNotificationProvider implements MediaNotification
// Skip to previous action.
boolean skipToPreviousAdded = false;
if (availableCommands.containsAny(
Player.COMMAND_SEEK_TO_PREVIOUS, Player.COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM)) {
COMMAND_SEEK_TO_PREVIOUS, COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM)) {
skipToPreviousAdded = true;
builder.addAction(
actionFactory.createMediaAction(
IconCompat.createWithResource(
context, R.drawable.media3_notification_seek_to_previous),
context.getString(R.string.media3_controls_seek_to_previous_description),
MediaNotification.ActionFactory.COMMAND_SKIP_TO_PREVIOUS));
COMMAND_SEEK_TO_PREVIOUS));
}
boolean playPauseAdded = false;
if (availableCommands.contains(Player.COMMAND_PLAY_PAUSE)) {
if (availableCommands.contains(COMMAND_PLAY_PAUSE)) {
playPauseAdded = true;
if (mediaController.getPlaybackState() == Player.STATE_ENDED
|| !mediaController.getPlayWhenReady()) {
@ -139,24 +141,23 @@ public final class DefaultMediaNotificationProvider implements MediaNotification
actionFactory.createMediaAction(
IconCompat.createWithResource(context, R.drawable.media3_notification_play),
context.getString(R.string.media3_controls_play_description),
MediaNotification.ActionFactory.COMMAND_PLAY));
COMMAND_PLAY_PAUSE));
} else {
// Pause action.
builder.addAction(
actionFactory.createMediaAction(
IconCompat.createWithResource(context, R.drawable.media3_notification_pause),
context.getString(R.string.media3_controls_pause_description),
MediaNotification.ActionFactory.COMMAND_PAUSE));
COMMAND_PLAY_PAUSE));
}
}
// Skip to next action.
if (availableCommands.containsAny(
Player.COMMAND_SEEK_TO_NEXT, Player.COMMAND_SEEK_TO_NEXT_MEDIA_ITEM)) {
if (availableCommands.containsAny(COMMAND_SEEK_TO_NEXT, COMMAND_SEEK_TO_NEXT_MEDIA_ITEM)) {
builder.addAction(
actionFactory.createMediaAction(
IconCompat.createWithResource(context, R.drawable.media3_notification_seek_to_next),
context.getString(R.string.media3_controls_seek_to_next_description),
MediaNotification.ActionFactory.COMMAND_SKIP_TO_NEXT));
COMMAND_SEEK_TO_NEXT));
}
// Set metadata info in the notification.
@ -187,11 +188,9 @@ public final class DefaultMediaNotificationProvider implements MediaNotification
}
MediaStyle mediaStyle = new MediaStyle();
if (mediaController.isCommandAvailable(Player.COMMAND_STOP) || Util.SDK_INT < 21) {
if (mediaController.isCommandAvailable(COMMAND_STOP) || Util.SDK_INT < 21) {
// We must include a cancel intent for pre-L devices.
mediaStyle.setCancelButtonIntent(
actionFactory.createMediaActionPendingIntent(
MediaNotification.ActionFactory.COMMAND_STOP));
mediaStyle.setCancelButtonIntent(actionFactory.createMediaActionPendingIntent(COMMAND_STOP));
}
if (playPauseAdded) {
// Show play/pause button only in compact view.
@ -208,9 +207,7 @@ public final class DefaultMediaNotificationProvider implements MediaNotification
Notification notification =
builder
.setContentIntent(mediaController.getSessionActivity())
.setDeleteIntent(
actionFactory.createMediaActionPendingIntent(
MediaNotification.ActionFactory.COMMAND_STOP))
.setDeleteIntent(actionFactory.createMediaActionPendingIntent(COMMAND_STOP))
.setOnlyAlertOnce(true)
.setSmallIcon(getSmallIconResId(context))
.setStyle(mediaStyle)

View File

@ -16,22 +16,16 @@
package androidx.media3.session;
import static androidx.media3.common.util.Assertions.checkNotNull;
import static java.lang.annotation.ElementType.TYPE_USE;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.os.Bundle;
import android.support.v4.media.session.PlaybackStateCompat;
import androidx.annotation.IntRange;
import androidx.annotation.LongDef;
import androidx.core.app.NotificationCompat;
import androidx.core.graphics.drawable.IconCompat;
import androidx.media3.common.Player;
import androidx.media3.common.util.UnstableApi;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/** A notification for media playbacks. */
public final class MediaNotification {
@ -43,44 +37,6 @@ public final class MediaNotification {
@UnstableApi
public interface ActionFactory {
/**
* Commands that can be included in a media action. One of {@link #COMMAND_PLAY}, {@link
* #COMMAND_PAUSE}, {@link #COMMAND_STOP}, {@link #COMMAND_REWIND}, {@link
* #COMMAND_FAST_FORWARD}, {@link #COMMAND_SKIP_TO_PREVIOUS}, {@link #COMMAND_SKIP_TO_NEXT} or
* {@link #COMMAND_SET_CAPTIONING_ENABLED}.
*/
@Documented
@Retention(RetentionPolicy.SOURCE)
@Target({TYPE_USE})
@LongDef({
COMMAND_PLAY,
COMMAND_PAUSE,
COMMAND_STOP,
COMMAND_REWIND,
COMMAND_FAST_FORWARD,
COMMAND_SKIP_TO_PREVIOUS,
COMMAND_SKIP_TO_NEXT,
COMMAND_SET_CAPTIONING_ENABLED
})
@interface Command {}
/** The command to start playback. */
long COMMAND_PLAY = PlaybackStateCompat.ACTION_PLAY;
/** The command to pause playback. */
long COMMAND_PAUSE = PlaybackStateCompat.ACTION_PAUSE;
/** The command to stop playback. */
long COMMAND_STOP = PlaybackStateCompat.ACTION_STOP;
/** The command to rewind. */
long COMMAND_REWIND = PlaybackStateCompat.ACTION_REWIND;
/** The command to fast forward. */
long COMMAND_FAST_FORWARD = PlaybackStateCompat.ACTION_FAST_FORWARD;
/** The command to skip to the previous item in the queue. */
long COMMAND_SKIP_TO_PREVIOUS = PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS;
/** The command to skip to the next item in the queue. */
long COMMAND_SKIP_TO_NEXT = PlaybackStateCompat.ACTION_SKIP_TO_NEXT;
/** The command to set captioning enabled. */
long COMMAND_SET_CAPTIONING_ENABLED = PlaybackStateCompat.ACTION_SET_CAPTIONING_ENABLED;
/**
* Creates a {@link NotificationCompat.Action} for a notification. These actions will be handled
* by the library.
@ -90,7 +46,7 @@ public final class MediaNotification {
* @param command A command to send when users trigger this action.
*/
NotificationCompat.Action createMediaAction(
IconCompat icon, CharSequence title, @Command long command);
IconCompat icon, CharSequence title, @Player.Command long command);
/**
* Creates a {@link NotificationCompat.Action} for a notification with a custom action. Actions
@ -112,7 +68,7 @@ public final class MediaNotification {
*
* @param command The intent's command.
*/
PendingIntent createMediaActionPendingIntent(@Command long command);
PendingIntent createMediaActionPendingIntent(@Player.Command long command);
}
/**

View File

@ -21,6 +21,7 @@ import static org.robolectric.Shadows.shadowOf;
import android.app.PendingIntent;
import android.content.Intent;
import androidx.annotation.Nullable;
import androidx.media3.common.Player;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
@ -37,7 +38,7 @@ public class DefaultActionFactoryTest {
new DefaultActionFactory(Robolectric.setupService(TestService.class));
PendingIntent pendingIntent =
actionFactory.createMediaActionPendingIntent(MediaNotification.ActionFactory.COMMAND_PLAY);
actionFactory.createMediaActionPendingIntent(Player.COMMAND_PLAY_PAUSE);
ShadowPendingIntent shadowPendingIntent = shadowOf(pendingIntent);
assertThat(actionFactory.isMediaAction(shadowPendingIntent.getSavedIntent())).isTrue();