Add icon constants to CommandButton
These allow to set the icon in a standardized way without needing custom bitmaps or resources. For now, this is just additional information without backwards-compatible icons or implications. The same value gets written to the platform session via a new extras key that can be read and set from sessions not using Media3 yet. PiperOrigin-RevId: 605670988
This commit is contained in:
parent
338aef4830
commit
adc23e8e8b
@ -18,11 +18,13 @@ package androidx.media3.session;
|
||||
import static androidx.media3.common.util.Assertions.checkArgument;
|
||||
import static androidx.media3.common.util.Assertions.checkNotNull;
|
||||
import static androidx.media3.common.util.Assertions.checkState;
|
||||
import static java.lang.annotation.ElementType.TYPE_USE;
|
||||
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.text.TextUtils;
|
||||
import androidx.annotation.DrawableRes;
|
||||
import androidx.annotation.IntDef;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.media3.common.Bundleable;
|
||||
import androidx.media3.common.Player;
|
||||
@ -32,6 +34,10 @@ import com.google.common.base.Objects;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.errorprone.annotations.CanIgnoreReturnValue;
|
||||
import com.google.errorprone.annotations.CheckReturnValue;
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@ -43,11 +49,343 @@ import java.util.List;
|
||||
*/
|
||||
public final class CommandButton implements Bundleable {
|
||||
|
||||
/** An icon constant for a button. Must be one of the {@code CommandButton.ICON_} constants. */
|
||||
@UnstableApi
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@Target(TYPE_USE)
|
||||
@IntDef({
|
||||
ICON_UNDEFINED,
|
||||
ICON_PLAY,
|
||||
ICON_PAUSE,
|
||||
ICON_STOP,
|
||||
ICON_NEXT,
|
||||
ICON_PREVIOUS,
|
||||
ICON_SKIP_FORWARD,
|
||||
ICON_SKIP_FORWARD_5,
|
||||
ICON_SKIP_FORWARD_10,
|
||||
ICON_SKIP_FORWARD_15,
|
||||
ICON_SKIP_FORWARD_30,
|
||||
ICON_SKIP_BACK,
|
||||
ICON_SKIP_BACK_5,
|
||||
ICON_SKIP_BACK_10,
|
||||
ICON_SKIP_BACK_15,
|
||||
ICON_SKIP_BACK_30,
|
||||
ICON_FAST_FORWARD,
|
||||
ICON_REWIND,
|
||||
ICON_REPEAT_ALL,
|
||||
ICON_REPEAT_ONE,
|
||||
ICON_SHUFFLE,
|
||||
ICON_SHUFFLE_STAR,
|
||||
ICON_HEART_FILLED,
|
||||
ICON_HEART_UNFILLED,
|
||||
ICON_STAR_FILLED,
|
||||
ICON_STAR_UNFILLED,
|
||||
ICON_BOOKMARK_FILLED,
|
||||
ICON_BOOKMARK_UNFILLED,
|
||||
ICON_THUMB_UP_FILLED,
|
||||
ICON_THUMB_UP_UNFILLED,
|
||||
ICON_THUMB_DOWN_FILLED,
|
||||
ICON_THUMB_DOWN_UNFILLED,
|
||||
ICON_FLAG_FILLED,
|
||||
ICON_FLAG_UNFILLED,
|
||||
ICON_PLUS,
|
||||
ICON_MINUS,
|
||||
ICON_PLAYLIST_ADD,
|
||||
ICON_PLAYLIST_REMOVE,
|
||||
ICON_BLOCK,
|
||||
ICON_PLUS_CIRCLE_FILLED,
|
||||
ICON_PLUS_CIRCLE_UNFILLED,
|
||||
ICON_MINUS_CIRCLE_FILLED,
|
||||
ICON_MINUS_CIRCLE_UNFILLED,
|
||||
ICON_CHECK_CIRCLE_FILLED,
|
||||
ICON_CHECK_CIRCLE_UNFILLED,
|
||||
ICON_PLAYBACK_SPEED,
|
||||
ICON_PLAYBACK_SPEED_0_5,
|
||||
ICON_PLAYBACK_SPEED_0_8,
|
||||
ICON_PLAYBACK_SPEED_1_0,
|
||||
ICON_PLAYBACK_SPEED_1_2,
|
||||
ICON_PLAYBACK_SPEED_1_5,
|
||||
ICON_PLAYBACK_SPEED_1_8,
|
||||
ICON_PLAYBACK_SPEED_2_0,
|
||||
ICON_SETTINGS,
|
||||
ICON_QUALITY,
|
||||
ICON_SUBTITLES,
|
||||
ICON_SUBTITLES_OFF,
|
||||
ICON_CLOSED_CAPTIONS,
|
||||
ICON_CLOSED_CAPTIONS_OFF,
|
||||
ICON_SYNC,
|
||||
ICON_SHARE,
|
||||
ICON_VOLUME_UP,
|
||||
ICON_VOLUME_DOWN,
|
||||
ICON_VOLUME_OFF,
|
||||
ICON_ARTIST,
|
||||
ICON_ALBUM,
|
||||
ICON_RADIO,
|
||||
ICON_SIGNAL,
|
||||
ICON_FEED
|
||||
})
|
||||
public @interface Icon {}
|
||||
|
||||
// Note: The constant values of these icons matches the Material Design code points.
|
||||
|
||||
/**
|
||||
* An icon constant representing an undefined icon, for example a custom icon not covered by the
|
||||
* existing constants.
|
||||
*/
|
||||
@UnstableApi public static final int ICON_UNDEFINED = 0;
|
||||
|
||||
/** An icon showing a play symbol (a right facing triangle). */
|
||||
@UnstableApi public static final int ICON_PLAY = 0xe037;
|
||||
|
||||
/** An icon showing a pause symbol (two vertical bars). */
|
||||
@UnstableApi public static final int ICON_PAUSE = 0xe034;
|
||||
|
||||
/** An icon showing a stop symbol (a square). */
|
||||
@UnstableApi public static final int ICON_STOP = 0xe047;
|
||||
|
||||
/** An icon showing a next symbol (a right facing triangle with a vertical bar). */
|
||||
@UnstableApi public static final int ICON_NEXT = 0xe044;
|
||||
|
||||
/** An icon showing a previous symbol (a left facing triangle with a vertical bar). */
|
||||
@UnstableApi public static final int ICON_PREVIOUS = 0xe045;
|
||||
|
||||
/** An icon showing a skip forward symbol (an open clock-wise arrow). */
|
||||
@UnstableApi public static final int ICON_SKIP_FORWARD = 0xf6f4;
|
||||
|
||||
/**
|
||||
* An icon showing a skip forward 5 seconds symbol (an open clockwise arrow with the number 5).
|
||||
*/
|
||||
@UnstableApi public static final int ICON_SKIP_FORWARD_5 = 0xe058;
|
||||
|
||||
/**
|
||||
* An icon showing a skip forward 10 seconds symbol (an open clockwise arrow with the number 10).
|
||||
*/
|
||||
@UnstableApi public static final int ICON_SKIP_FORWARD_10 = 0xe056;
|
||||
|
||||
/**
|
||||
* An icon showing a skip forward 15 seconds symbol (an open clockwise arrow with the number 15).
|
||||
*/
|
||||
@UnstableApi public static final int ICON_SKIP_FORWARD_15 = 0xfe056;
|
||||
|
||||
/**
|
||||
* An icon showing a skip forward 30 seconds symbol (an open clockwise arrow with the number 30).
|
||||
*/
|
||||
@UnstableApi public static final int ICON_SKIP_FORWARD_30 = 0xe057;
|
||||
|
||||
/** An icon showing a skip back symbol (an open anti-clockwise arrow). */
|
||||
@UnstableApi public static final int ICON_SKIP_BACK = 0xe042;
|
||||
|
||||
/**
|
||||
* An icon showing a skip back 5 seconds symbol (an open anti-clockwise arrow with the number 5).
|
||||
*/
|
||||
@UnstableApi public static final int ICON_SKIP_BACK_5 = 0xe05b;
|
||||
|
||||
/**
|
||||
* An icon showing a skip back 10 seconds symbol (an open anti-clockwise arrow with the number
|
||||
* 10).
|
||||
*/
|
||||
@UnstableApi public static final int ICON_SKIP_BACK_10 = 0xe059;
|
||||
|
||||
/**
|
||||
* An icon showing a skip back 15 seconds symbol (an open anti-clockwise arrow with the number
|
||||
* 15).
|
||||
*/
|
||||
@UnstableApi public static final int ICON_SKIP_BACK_15 = 0xfe059;
|
||||
|
||||
/**
|
||||
* An icon showing a skip back 30 seconds symbol (an open anti-clockwise arrow with the number
|
||||
* 30).
|
||||
*/
|
||||
@UnstableApi public static final int ICON_SKIP_BACK_30 = 0xe05a;
|
||||
|
||||
/** An icon showing a fast forward symbol (two right facing triangles). */
|
||||
@UnstableApi public static final int ICON_FAST_FORWARD = 0xe01f;
|
||||
|
||||
/** An icon showing a rewind symbol (two left facing triangles). */
|
||||
@UnstableApi public static final int ICON_REWIND = 0xe020;
|
||||
|
||||
/** An icon showing a repeat all symbol (two open clockwise arrows). */
|
||||
@UnstableApi public static final int ICON_REPEAT_ALL = 0xe040;
|
||||
|
||||
/** An icon showing a repeat one symbol (two open clockwise arrows with an overlaid number 1). */
|
||||
@UnstableApi public static final int ICON_REPEAT_ONE = 0xe041;
|
||||
|
||||
/** An icon showing a shuffle symbol (two diagonal upward and downward facing arrows). */
|
||||
@UnstableApi public static final int ICON_SHUFFLE = 0xe043;
|
||||
|
||||
/**
|
||||
* An icon showing a shuffle symbol with a start (two diagonal upward and downward facing arrows
|
||||
* with an overlaid star).
|
||||
*/
|
||||
@UnstableApi public static final int ICON_SHUFFLE_STAR = 0xfe043;
|
||||
|
||||
/** An icon showing a filled heart symbol. */
|
||||
@UnstableApi public static final int ICON_HEART_FILLED = 0xfe87d;
|
||||
|
||||
/** An icon showing an unfilled heart symbol. */
|
||||
@UnstableApi public static final int ICON_HEART_UNFILLED = 0xe87d;
|
||||
|
||||
/** An icon showing a filled star symbol. */
|
||||
@UnstableApi public static final int ICON_STAR_FILLED = 0xfe838;
|
||||
|
||||
/** An icon showing an unfilled star symbol. */
|
||||
@UnstableApi public static final int ICON_STAR_UNFILLED = 0xe838;
|
||||
|
||||
/** An icon showing a filled bookmark symbol. */
|
||||
@UnstableApi public static final int ICON_BOOKMARK_FILLED = 0xfe866;
|
||||
|
||||
/** An icon showing an unfilled bookmark symbol. */
|
||||
@UnstableApi public static final int ICON_BOOKMARK_UNFILLED = 0xe866;
|
||||
|
||||
/** An icon showing a filled thumb-up symbol. */
|
||||
@UnstableApi public static final int ICON_THUMB_UP_FILLED = 0xfe8dc;
|
||||
|
||||
/** An icon showing an unfilled thumb-up symbol. */
|
||||
@UnstableApi public static final int ICON_THUMB_UP_UNFILLED = 0xe8dc;
|
||||
|
||||
/** An icon showing a filled thumb-down symbol. */
|
||||
@UnstableApi public static final int ICON_THUMB_DOWN_FILLED = 0xfe8db;
|
||||
|
||||
/** An icon showing an unfilled thumb-down symbol. */
|
||||
@UnstableApi public static final int ICON_THUMB_DOWN_UNFILLED = 0xe8db;
|
||||
|
||||
/** An icon showing a filled flag symbol. */
|
||||
@UnstableApi public static final int ICON_FLAG_FILLED = 0xfe153;
|
||||
|
||||
/** An icon showing an unfilled flag symbol. */
|
||||
@UnstableApi public static final int ICON_FLAG_UNFILLED = 0xe153;
|
||||
|
||||
/** An icon showing a plus symbol. */
|
||||
@UnstableApi public static final int ICON_PLUS = 0xe145;
|
||||
|
||||
/** An icon showing a minus symbol. */
|
||||
@UnstableApi public static final int ICON_MINUS = 0xe15b;
|
||||
|
||||
/** An icon showing an add to playlist symbol (multiple horizontal bars with a small plus). */
|
||||
@UnstableApi public static final int ICON_PLAYLIST_ADD = 0xe03b;
|
||||
|
||||
/**
|
||||
* An icon showing an remove from playlist symbol (multiple horizontal bars with a small minus).
|
||||
*/
|
||||
@UnstableApi public static final int ICON_PLAYLIST_REMOVE = 0xeb80;
|
||||
|
||||
/** An icon showing a block symbol (a circle with a diagonal line). */
|
||||
@UnstableApi public static final int ICON_BLOCK = 0xe14b;
|
||||
|
||||
/** An icon showing a filled circle with a plus. */
|
||||
@UnstableApi public static final int ICON_PLUS_CIRCLE_FILLED = 0xfe147;
|
||||
|
||||
/** An icon showing an unfilled circle with a plus. */
|
||||
@UnstableApi public static final int ICON_PLUS_CIRCLE_UNFILLED = 0xe147;
|
||||
|
||||
/** An icon showing a filled circle with a minus. */
|
||||
@UnstableApi public static final int ICON_MINUS_CIRCLE_FILLED = 0xfe148;
|
||||
|
||||
/** An icon showing an unfilled circle with a minus. */
|
||||
@UnstableApi public static final int ICON_MINUS_CIRCLE_UNFILLED = 0xfe149;
|
||||
|
||||
/** An icon showing a filled circle with a check mark. */
|
||||
@UnstableApi public static final int ICON_CHECK_CIRCLE_FILLED = 0xfe86c;
|
||||
|
||||
/** An icon showing a unfilled circle with a check mark. */
|
||||
@UnstableApi public static final int ICON_CHECK_CIRCLE_UNFILLED = 0xe86c;
|
||||
|
||||
/**
|
||||
* An icon showing a playback speed symbol (a right facing triangle in a circle with half-dashed,
|
||||
* half-solid contour).
|
||||
*/
|
||||
@UnstableApi public static final int ICON_PLAYBACK_SPEED = 0xe068;
|
||||
|
||||
/** An icon showing a 0.5x speed symbol. */
|
||||
@UnstableApi public static final int ICON_PLAYBACK_SPEED_0_5 = 0xf4e2;
|
||||
|
||||
/** An icon showing a 0.8x speed symbol. */
|
||||
@UnstableApi public static final int ICON_PLAYBACK_SPEED_0_8 = 0xff4e2;
|
||||
|
||||
/** An icon showing a 1.0x speed symbol. */
|
||||
@UnstableApi public static final int ICON_PLAYBACK_SPEED_1_0 = 0xefcd;
|
||||
|
||||
/** An icon showing a 1.2x speed symbol. */
|
||||
@UnstableApi public static final int ICON_PLAYBACK_SPEED_1_2 = 0xf4e1;
|
||||
|
||||
/** An icon showing a 1.5x speed symbol. */
|
||||
@UnstableApi public static final int ICON_PLAYBACK_SPEED_1_5 = 0xf4e0;
|
||||
|
||||
/** An icon showing a 1.8x speed symbol. */
|
||||
@UnstableApi public static final int ICON_PLAYBACK_SPEED_1_8 = 0xff4e0;
|
||||
|
||||
/** An icon showing a 2.0x speed symbol. */
|
||||
@UnstableApi public static final int ICON_PLAYBACK_SPEED_2_0 = 0xf4eb;
|
||||
|
||||
/** An icon showing a settings symbol (a stylized cog). */
|
||||
@UnstableApi public static final int ICON_SETTINGS = 0xe8b8;
|
||||
|
||||
/** An icon showing a quality selection symbol (multiple horizontal bars with sliders). */
|
||||
@UnstableApi public static final int ICON_QUALITY = 0xe429;
|
||||
|
||||
/** An icon showing a subtitles symbol (a rectangle filled with dots and horizontal lines). */
|
||||
@UnstableApi public static final int ICON_SUBTITLES = 0xe048;
|
||||
|
||||
/**
|
||||
* An icon showing a subtitles off symbol (a rectangle filled with dots and horizontal lines, with
|
||||
* a large diagonal line across).
|
||||
*/
|
||||
@UnstableApi public static final int ICON_SUBTITLES_OFF = 0xef72;
|
||||
|
||||
/** An icon showing a closed caption symbol (a rectangle with the letters CC). */
|
||||
@UnstableApi public static final int ICON_CLOSED_CAPTIONS = 0xe01c;
|
||||
|
||||
/**
|
||||
* An icon showing a closed caption off symbol (a rectangle with the letters CC, with a large
|
||||
* diagonal line across).
|
||||
*/
|
||||
@UnstableApi public static final int ICON_CLOSED_CAPTIONS_OFF = 0xf1dc;
|
||||
|
||||
/** An icon showing a sync symbol (two open anti-clockwise arrows). */
|
||||
@UnstableApi public static final int ICON_SYNC = 0xe627;
|
||||
|
||||
/**
|
||||
* An icon showing a share symbol (three dots connected by two diagonal lines, open on the right).
|
||||
*/
|
||||
@UnstableApi public static final int ICON_SHARE = 0xe80d;
|
||||
|
||||
/** An icon showing a volume up symbol (a stylized speaker with multiple sound waves). */
|
||||
@UnstableApi public static final int ICON_VOLUME_UP = 0xe050;
|
||||
|
||||
/** An icon showing a volume down symbol (a stylized speaker with a single small sound wave). */
|
||||
@UnstableApi public static final int ICON_VOLUME_DOWN = 0xe04d;
|
||||
|
||||
/**
|
||||
* An icon showing a volume off symbol (a stylized speaker with multiple sound waves, with a large
|
||||
* diagonal line across).
|
||||
*/
|
||||
@UnstableApi public static final int ICON_VOLUME_OFF = 0xe04f;
|
||||
|
||||
/** An icon showing an artist symbol (a stylized person with a musical note). */
|
||||
@UnstableApi public static final int ICON_ARTIST = 0xe01a;
|
||||
|
||||
/** An icon showing an album symbol (a stylized LP record). */
|
||||
@UnstableApi public static final int ICON_ALBUM = 0xe019;
|
||||
|
||||
/** An icon showing a radio symbol (left and right facing sound waves). */
|
||||
@UnstableApi public static final int ICON_RADIO = 0xe51e;
|
||||
|
||||
/** An icon showing an signal symbol (a vertical mast with circular sounds waves). */
|
||||
@UnstableApi public static final int ICON_SIGNAL = 0xf048;
|
||||
|
||||
/**
|
||||
* An icon showing an feed symbol (a dot in the bottom-left with multiple concentric quarter
|
||||
* circles).
|
||||
*/
|
||||
@UnstableApi public static final int ICON_FEED = 0xe0e5;
|
||||
|
||||
/** A builder for {@link CommandButton}. */
|
||||
public static final class Builder {
|
||||
|
||||
@Nullable private SessionCommand sessionCommand;
|
||||
private @Player.Command int playerCommand;
|
||||
private @Icon int icon;
|
||||
@DrawableRes private int iconResId;
|
||||
@Nullable private Uri iconUri;
|
||||
private CharSequence displayName;
|
||||
@ -59,6 +397,7 @@ public final class CommandButton implements Bundleable {
|
||||
displayName = "";
|
||||
extras = Bundle.EMPTY;
|
||||
playerCommand = Player.COMMAND_INVALID;
|
||||
icon = ICON_UNDEFINED;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -97,6 +436,19 @@ public final class CommandButton implements Bundleable {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the icon of this button.
|
||||
*
|
||||
* @param icon The {@link Icon} that should be shown for this button.
|
||||
* @return This builder for chaining.
|
||||
*/
|
||||
@UnstableApi
|
||||
@CanIgnoreReturnValue
|
||||
public Builder setIcon(@Icon int icon) {
|
||||
this.icon = icon;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the resource id of a bitmap (e.g. PNG) icon of this button.
|
||||
*
|
||||
@ -168,7 +520,7 @@ public final class CommandButton implements Bundleable {
|
||||
(sessionCommand == null) != (playerCommand == Player.COMMAND_INVALID),
|
||||
"Exactly one of sessionCommand and playerCommand should be set");
|
||||
return new CommandButton(
|
||||
sessionCommand, playerCommand, iconResId, iconUri, displayName, extras, enabled);
|
||||
sessionCommand, playerCommand, icon, iconResId, iconUri, displayName, extras, enabled);
|
||||
}
|
||||
}
|
||||
|
||||
@ -181,6 +533,9 @@ public final class CommandButton implements Bundleable {
|
||||
*/
|
||||
public final @Player.Command int playerCommand;
|
||||
|
||||
/** The {@link Icon} of the button. */
|
||||
@UnstableApi public final @Icon int icon;
|
||||
|
||||
/**
|
||||
* The icon resource id of the button. Can be {@code 0} if the command is predefined and a custom
|
||||
* icon isn't needed.
|
||||
@ -208,6 +563,7 @@ public final class CommandButton implements Bundleable {
|
||||
private CommandButton(
|
||||
@Nullable SessionCommand sessionCommand,
|
||||
@Player.Command int playerCommand,
|
||||
@Icon int icon,
|
||||
@DrawableRes int iconResId,
|
||||
@Nullable Uri iconUri,
|
||||
CharSequence displayName,
|
||||
@ -215,6 +571,7 @@ public final class CommandButton implements Bundleable {
|
||||
boolean enabled) {
|
||||
this.sessionCommand = sessionCommand;
|
||||
this.playerCommand = playerCommand;
|
||||
this.icon = icon;
|
||||
this.iconResId = iconResId;
|
||||
this.iconUri = iconUri;
|
||||
this.displayName = displayName;
|
||||
@ -234,6 +591,7 @@ public final class CommandButton implements Bundleable {
|
||||
return new CommandButton(
|
||||
sessionCommand,
|
||||
playerCommand,
|
||||
icon,
|
||||
iconResId,
|
||||
iconUri,
|
||||
displayName,
|
||||
@ -253,6 +611,7 @@ public final class CommandButton implements Bundleable {
|
||||
CommandButton button = (CommandButton) obj;
|
||||
return Objects.equal(sessionCommand, button.sessionCommand)
|
||||
&& playerCommand == button.playerCommand
|
||||
&& icon == button.icon
|
||||
&& iconResId == button.iconResId
|
||||
&& Objects.equal(iconUri, button.iconUri)
|
||||
&& TextUtils.equals(displayName, button.displayName)
|
||||
@ -262,7 +621,7 @@ public final class CommandButton implements Bundleable {
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hashCode(
|
||||
sessionCommand, playerCommand, iconResId, displayName, isEnabled, iconUri);
|
||||
sessionCommand, playerCommand, icon, iconResId, displayName, isEnabled, iconUri);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -307,6 +666,7 @@ public final class CommandButton implements Bundleable {
|
||||
private static final String FIELD_EXTRAS = Util.intToStringMaxRadix(4);
|
||||
private static final String FIELD_ENABLED = Util.intToStringMaxRadix(5);
|
||||
private static final String FIELD_ICON_URI = Util.intToStringMaxRadix(6);
|
||||
private static final String FIELD_ICON = Util.intToStringMaxRadix(7);
|
||||
|
||||
@UnstableApi
|
||||
@Override
|
||||
@ -315,12 +675,27 @@ public final class CommandButton implements Bundleable {
|
||||
if (sessionCommand != null) {
|
||||
bundle.putBundle(FIELD_SESSION_COMMAND, sessionCommand.toBundle());
|
||||
}
|
||||
bundle.putInt(FIELD_PLAYER_COMMAND, playerCommand);
|
||||
bundle.putInt(FIELD_ICON_RES_ID, iconResId);
|
||||
bundle.putCharSequence(FIELD_DISPLAY_NAME, displayName);
|
||||
bundle.putBundle(FIELD_EXTRAS, extras);
|
||||
bundle.putParcelable(FIELD_ICON_URI, iconUri);
|
||||
bundle.putBoolean(FIELD_ENABLED, isEnabled);
|
||||
if (playerCommand != Player.COMMAND_INVALID) {
|
||||
bundle.putInt(FIELD_PLAYER_COMMAND, playerCommand);
|
||||
}
|
||||
if (icon != ICON_UNDEFINED) {
|
||||
bundle.putInt(FIELD_ICON, icon);
|
||||
}
|
||||
if (iconResId != 0) {
|
||||
bundle.putInt(FIELD_ICON_RES_ID, iconResId);
|
||||
}
|
||||
if (displayName != "") {
|
||||
bundle.putCharSequence(FIELD_DISPLAY_NAME, displayName);
|
||||
}
|
||||
if (!extras.isEmpty()) {
|
||||
bundle.putBundle(FIELD_EXTRAS, extras);
|
||||
}
|
||||
if (iconUri != null) {
|
||||
bundle.putParcelable(FIELD_ICON_URI, iconUri);
|
||||
}
|
||||
if (isEnabled) {
|
||||
bundle.putBoolean(FIELD_ENABLED, isEnabled);
|
||||
}
|
||||
return bundle;
|
||||
}
|
||||
|
||||
@ -349,6 +724,7 @@ public final class CommandButton implements Bundleable {
|
||||
@Nullable Bundle extras = bundle.getBundle(FIELD_EXTRAS);
|
||||
boolean enabled = bundle.getBoolean(FIELD_ENABLED, /* defaultValue= */ false);
|
||||
@Nullable Uri iconUri = bundle.getParcelable(FIELD_ICON_URI);
|
||||
@Icon int icon = bundle.getInt(FIELD_ICON, /* defaultValue= */ ICON_UNDEFINED);
|
||||
Builder builder = new Builder();
|
||||
if (sessionCommand != null) {
|
||||
builder.setSessionCommand(sessionCommand);
|
||||
@ -360,6 +736,7 @@ public final class CommandButton implements Bundleable {
|
||||
builder.setIconUri(iconUri);
|
||||
}
|
||||
return builder
|
||||
.setIcon(icon)
|
||||
.setIconResId(iconResId)
|
||||
.setDisplayName(displayName)
|
||||
.setExtras(extras == null ? Bundle.EMPTY : extras)
|
||||
|
@ -1258,11 +1258,19 @@ import java.util.concurrent.TimeoutException;
|
||||
for (CustomAction customAction : state.getCustomActions()) {
|
||||
String action = customAction.getAction();
|
||||
@Nullable Bundle extras = customAction.getExtras();
|
||||
@CommandButton.Icon
|
||||
int icon =
|
||||
extras != null
|
||||
? extras.getInt(
|
||||
MediaConstants.EXTRAS_KEY_COMMAND_BUTTON_ICON_COMPAT,
|
||||
/* defaultValue= */ CommandButton.ICON_UNDEFINED)
|
||||
: CommandButton.ICON_UNDEFINED;
|
||||
CommandButton button =
|
||||
new CommandButton.Builder()
|
||||
.setSessionCommand(new SessionCommand(action, extras == null ? Bundle.EMPTY : extras))
|
||||
.setDisplayName(customAction.getName())
|
||||
.setEnabled(true)
|
||||
.setIcon(icon)
|
||||
.setIconResId(customAction.getIcon())
|
||||
.build();
|
||||
layout.add(button);
|
||||
|
@ -465,6 +465,15 @@ public final class MediaConstants {
|
||||
public static final String EXTRAS_KEY_MEDIA_TYPE_COMPAT =
|
||||
"androidx.media3.session.EXTRAS_KEY_MEDIA_TYPE_COMPAT";
|
||||
|
||||
/**
|
||||
* {@link Bundle} key used to indicate the {@link CommandButton.Icon} in the extras of the legacy
|
||||
* {@link PlaybackStateCompat.CustomAction}. The corresponding value should be one of the {@code
|
||||
* CommandButton.ICON_} integer constants.
|
||||
*/
|
||||
@UnstableApi
|
||||
public static final String EXTRAS_KEY_COMMAND_BUTTON_ICON_COMPAT =
|
||||
"androidx.media3.session.EXTRAS_KEY_COMMAND_BUTTON_ICON_COMPAT";
|
||||
|
||||
/* package */ static final String SESSION_COMMAND_ON_CAPTIONING_ENABLED_CHANGED =
|
||||
"androidx.media3.session.SESSION_COMMAND_ON_CAPTIONING_ENABLED_CHANGED";
|
||||
/* package */ static final String SESSION_COMMAND_REQUEST_SESSION3_TOKEN =
|
||||
|
@ -1048,12 +1048,18 @@ import java.util.List;
|
||||
if (sessionCommand.commandCode == SessionCommand.COMMAND_CODE_CUSTOM
|
||||
&& CommandButton.isEnabled(
|
||||
commandButton, availableSessionCommands, availablePlayerCommands)) {
|
||||
Bundle actionExtras = sessionCommand.customExtras;
|
||||
if (commandButton.icon != CommandButton.ICON_UNDEFINED) {
|
||||
actionExtras = new Bundle(sessionCommand.customExtras);
|
||||
actionExtras.putInt(
|
||||
MediaConstants.EXTRAS_KEY_COMMAND_BUTTON_ICON_COMPAT, commandButton.icon);
|
||||
}
|
||||
builder.addCustomAction(
|
||||
new PlaybackStateCompat.CustomAction.Builder(
|
||||
sessionCommand.customAction,
|
||||
commandButton.displayName,
|
||||
commandButton.iconResId)
|
||||
.setExtras(sessionCommand.customExtras)
|
||||
.setExtras(actionExtras)
|
||||
.build());
|
||||
}
|
||||
}
|
||||
|
@ -242,6 +242,14 @@ public class CommandButtonTest {
|
||||
.setIconUri(Uri.parse("content://test"))
|
||||
.setPlayerCommand(Player.COMMAND_SEEK_TO_NEXT)
|
||||
.build());
|
||||
assertThat(button)
|
||||
.isNotEqualTo(
|
||||
new CommandButton.Builder()
|
||||
.setIcon(CommandButton.ICON_NEXT)
|
||||
.setDisplayName("button")
|
||||
.setIconResId(R.drawable.media3_notification_small_icon)
|
||||
.setPlayerCommand(Player.COMMAND_SEEK_TO_NEXT)
|
||||
.build());
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -360,4 +368,45 @@ public class CommandButtonTest {
|
||||
.setIconResId(R.drawable.media3_notification_small_icon);
|
||||
assertThrows(IllegalStateException.class, builder::build);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void fromBundle_afterToBundle_returnsEqualInstance() {
|
||||
Bundle extras = new Bundle();
|
||||
extras.putString("key", "value");
|
||||
CommandButton buttonWithSessionCommand =
|
||||
new CommandButton.Builder()
|
||||
.setDisplayName("name")
|
||||
.setEnabled(true)
|
||||
.setIcon(CommandButton.ICON_CLOSED_CAPTIONS)
|
||||
.setIconResId(R.drawable.media3_notification_small_icon)
|
||||
.setIconUri(Uri.parse("http://test.test"))
|
||||
.setExtras(extras)
|
||||
.setSessionCommand(new SessionCommand(SessionCommand.COMMAND_CODE_SESSION_SET_RATING))
|
||||
.build();
|
||||
CommandButton buttonWithPlayerCommand =
|
||||
new CommandButton.Builder()
|
||||
.setDisplayName("name")
|
||||
.setEnabled(true)
|
||||
.setIcon(CommandButton.ICON_CLOSED_CAPTIONS)
|
||||
.setIconResId(R.drawable.media3_notification_small_icon)
|
||||
.setIconUri(Uri.parse("http://test.test"))
|
||||
.setExtras(extras)
|
||||
.setPlayerCommand(Player.COMMAND_GET_METADATA)
|
||||
.build();
|
||||
CommandButton buttonWithDefaultValues =
|
||||
new CommandButton.Builder().setPlayerCommand(Player.COMMAND_PLAY_PAUSE).build();
|
||||
|
||||
CommandButton restoredButtonWithSessionCommand =
|
||||
CommandButton.fromBundle(buttonWithSessionCommand.toBundle());
|
||||
CommandButton restoredButtonWithPlayerCommand =
|
||||
CommandButton.fromBundle(buttonWithPlayerCommand.toBundle());
|
||||
CommandButton restoredButtonWithDefaultValues =
|
||||
CommandButton.fromBundle(buttonWithDefaultValues.toBundle());
|
||||
|
||||
assertThat(restoredButtonWithSessionCommand).isEqualTo(buttonWithSessionCommand);
|
||||
assertThat(restoredButtonWithSessionCommand.extras.get("key")).isEqualTo("value");
|
||||
assertThat(restoredButtonWithPlayerCommand).isEqualTo(buttonWithPlayerCommand);
|
||||
assertThat(restoredButtonWithPlayerCommand.extras.get("key")).isEqualTo("value");
|
||||
assertThat(restoredButtonWithDefaultValues).isEqualTo(buttonWithDefaultValues);
|
||||
}
|
||||
}
|
||||
|
@ -58,6 +58,7 @@ import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import androidx.test.filters.SdkSuppress;
|
||||
import androidx.test.filters.SmallTest;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
import java.util.List;
|
||||
import org.junit.Before;
|
||||
@ -895,23 +896,23 @@ public final class LegacyConversionsTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void convertToCustomLayout() {
|
||||
public void convertToCustomLayout_withNull_returnsEmptyList() {
|
||||
assertThat(LegacyConversions.convertToCustomLayout(null)).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void convertToCustomLayout_withoutIconConstantInExtras() {
|
||||
String extraKey = "key";
|
||||
String extraValue = "value";
|
||||
String actionStr = "action";
|
||||
String displayName = "display_name";
|
||||
int iconRes = 21;
|
||||
|
||||
Bundle extras = new Bundle();
|
||||
extras.putString(extraKey, extraValue);
|
||||
|
||||
PlaybackStateCompat.CustomAction action =
|
||||
new PlaybackStateCompat.CustomAction.Builder(actionStr, displayName, iconRes)
|
||||
.setExtras(extras)
|
||||
.build();
|
||||
|
||||
PlaybackStateCompat state =
|
||||
new PlaybackStateCompat.Builder()
|
||||
.setState(
|
||||
@ -922,7 +923,8 @@ public final class LegacyConversionsTest {
|
||||
.addCustomAction(action)
|
||||
.build();
|
||||
|
||||
List<CommandButton> buttons = LegacyConversions.convertToCustomLayout(state);
|
||||
ImmutableList<CommandButton> buttons = LegacyConversions.convertToCustomLayout(state);
|
||||
|
||||
assertThat(buttons).hasSize(1);
|
||||
CommandButton button = buttons.get(0);
|
||||
assertThat(button.displayName.toString()).isEqualTo(displayName);
|
||||
@ -930,6 +932,41 @@ public final class LegacyConversionsTest {
|
||||
assertThat(button.iconResId).isEqualTo(iconRes);
|
||||
assertThat(button.sessionCommand.customAction).isEqualTo(actionStr);
|
||||
assertThat(button.sessionCommand.customExtras.getString(extraKey)).isEqualTo(extraValue);
|
||||
assertThat(button.icon).isEqualTo(CommandButton.ICON_UNDEFINED);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void convertToCustomLayout_withIconConstantInExtras() {
|
||||
String actionStr = "action";
|
||||
String displayName = "display_name";
|
||||
int iconRes = 21;
|
||||
Bundle extras = new Bundle();
|
||||
extras.putInt(
|
||||
androidx.media3.session.MediaConstants.EXTRAS_KEY_COMMAND_BUTTON_ICON_COMPAT,
|
||||
CommandButton.ICON_FAST_FORWARD);
|
||||
PlaybackStateCompat.CustomAction action =
|
||||
new PlaybackStateCompat.CustomAction.Builder(actionStr, displayName, iconRes)
|
||||
.setExtras(extras)
|
||||
.build();
|
||||
PlaybackStateCompat state =
|
||||
new PlaybackStateCompat.Builder()
|
||||
.setState(
|
||||
PlaybackStateCompat.STATE_NONE,
|
||||
/* position= */ 0,
|
||||
/* playbackSpeed= */ 1,
|
||||
/* updateTime= */ 100)
|
||||
.addCustomAction(action)
|
||||
.build();
|
||||
|
||||
ImmutableList<CommandButton> buttons = LegacyConversions.convertToCustomLayout(state);
|
||||
|
||||
assertThat(buttons).hasSize(1);
|
||||
CommandButton button = buttons.get(0);
|
||||
assertThat(button.displayName.toString()).isEqualTo(displayName);
|
||||
assertThat(button.isEnabled).isTrue();
|
||||
assertThat(button.iconResId).isEqualTo(iconRes);
|
||||
assertThat(button.sessionCommand.customAction).isEqualTo(actionStr);
|
||||
assertThat(button.icon).isEqualTo(CommandButton.ICON_FAST_FORWARD);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -1563,6 +1563,7 @@ public class MediaControllerCompatPlaybackStateCompatActionsWithMediaSessionTest
|
||||
.build(),
|
||||
new CommandButton.Builder()
|
||||
.setDisplayName("button2")
|
||||
.setIcon(CommandButton.ICON_FAST_FORWARD)
|
||||
.setIconResId(R.drawable.media3_notification_pause)
|
||||
.setSessionCommand(command2)
|
||||
.build());
|
||||
|
@ -138,6 +138,8 @@ public class MediaControllerListenerWithMediaSessionCompatTest {
|
||||
.build();
|
||||
Bundle extras2 = new Bundle();
|
||||
extras2.putString("key", "value-2");
|
||||
extras2.putInt(
|
||||
MediaConstants.EXTRAS_KEY_COMMAND_BUTTON_ICON_COMPAT, CommandButton.ICON_FAST_FORWARD);
|
||||
PlaybackStateCompat.CustomAction customAction2 =
|
||||
new PlaybackStateCompat.CustomAction.Builder("action2", "actionName2", /* icon= */ 2)
|
||||
.setExtras(extras2)
|
||||
@ -151,6 +153,7 @@ public class MediaControllerListenerWithMediaSessionCompatTest {
|
||||
List<String> receivedBundleValues = new ArrayList<>();
|
||||
List<Integer> receivedIconResIds = new ArrayList<>();
|
||||
List<Integer> receivedCommandCodes = new ArrayList<>();
|
||||
List<Integer> receivedIcons = new ArrayList<>();
|
||||
CountDownLatch countDownLatch = new CountDownLatch(1);
|
||||
controllerTestRule.createController(
|
||||
session.getSessionToken(),
|
||||
@ -164,6 +167,7 @@ public class MediaControllerListenerWithMediaSessionCompatTest {
|
||||
receivedBundleValues.add(button.sessionCommand.customExtras.getString("key"));
|
||||
receivedCommandCodes.add(button.sessionCommand.commandCode);
|
||||
receivedIconResIds.add(button.iconResId);
|
||||
receivedIcons.add(button.icon);
|
||||
}
|
||||
countDownLatch.countDown();
|
||||
return Futures.immediateFuture(new SessionResult(SessionResult.RESULT_SUCCESS));
|
||||
@ -180,6 +184,9 @@ public class MediaControllerListenerWithMediaSessionCompatTest {
|
||||
assertThat(receivedDisplayNames).containsExactly("actionName1", "actionName2").inOrder();
|
||||
assertThat(receivedIconResIds).containsExactly(1, 2).inOrder();
|
||||
assertThat(receivedBundleValues).containsExactly("value-1", "value-2").inOrder();
|
||||
assertThat(receivedIcons)
|
||||
.containsExactly(CommandButton.ICON_UNDEFINED, CommandButton.ICON_FAST_FORWARD)
|
||||
.inOrder();
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -395,6 +402,7 @@ public class MediaControllerListenerWithMediaSessionCompatTest {
|
||||
CommandButton button2 =
|
||||
new CommandButton.Builder()
|
||||
.setDisplayName("button2")
|
||||
.setIcon(CommandButton.ICON_FAST_FORWARD)
|
||||
.setIconResId(R.drawable.media3_notification_small_icon)
|
||||
.setSessionCommand(new SessionCommand("command2", Bundle.EMPTY))
|
||||
.build();
|
||||
@ -431,6 +439,8 @@ public class MediaControllerListenerWithMediaSessionCompatTest {
|
||||
.build();
|
||||
Bundle extras2 = new Bundle();
|
||||
extras2.putString("key", "value-2");
|
||||
extras2.putInt(
|
||||
MediaConstants.EXTRAS_KEY_COMMAND_BUTTON_ICON_COMPAT, CommandButton.ICON_FAST_FORWARD);
|
||||
PlaybackStateCompat.CustomAction customAction2 =
|
||||
new PlaybackStateCompat.CustomAction.Builder(
|
||||
"command2", "button2", /* icon= */ R.drawable.media3_notification_small_icon)
|
||||
|
Loading…
x
Reference in New Issue
Block a user