Loading media/java/android/media/IMediaSession2Callback.aidl +2 −0 Original line number Diff line number Diff line Loading @@ -45,6 +45,8 @@ oneway interface IMediaSession2Callback { // TODO(jaewan): Is term 'accepted/rejected' correct? For permission, 'grant' is used. void onConnectionChanged(IMediaSession2 sessionBinder, in Bundle commandGroup); void onCustomLayoutChanged(in List<Bundle> commandButtonlist); ////////////////////////////////////////////////////////////////////////////////////////////// // Browser sepcific ////////////////////////////////////////////////////////////////////////////////////////////// Loading media/java/android/media/MediaController2.java +13 −0 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ package android.media; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; import android.media.MediaSession2.CommandButton; import android.media.MediaSession2.CommandGroup; import android.media.MediaSession2.ControllerInfo; import android.media.session.MediaSessionManager; Loading @@ -26,6 +27,8 @@ import android.media.session.PlaybackState; import android.media.update.ApiLoader; import android.media.update.MediaController2Provider; import android.os.Handler; import java.util.List; import java.util.concurrent.Executor; /** Loading Loading @@ -81,6 +84,16 @@ public class MediaController2 extends MediaPlayerBase { * You don't need to call {@link #release()} after this. */ public void onDisconnected() { } /** * Called when the session sets the custom layout through the * {@link MediaSession2#setCustomLayout(ControllerInfo, List)}. * <p> * Can be called before {@link #onConnected(CommandGroup)} is called. * * @param layout */ public void onCustomLayoutChanged(List<CommandButton> layout) { } } private final MediaController2Provider mProvider; Loading media/java/android/media/MediaSession2.java +196 −3 Original line number Diff line number Diff line Loading @@ -95,11 +95,11 @@ public class MediaSession2 extends MediaPlayerBase { // TODO(jaewan): Move this into the updatable. public static final class Command { private static final String KEY_COMMAND_CODE = "android.media.mediasession2.command.command_command"; = "android.media.media_session2.command.command_code"; private static final String KEY_COMMAND_CUSTOM_COMMAND = "android.media.mediasession2.command.custom_command"; = "android.media.media_session2.command.custom_command"; private static final String KEY_COMMAND_EXTRA = "android.media.mediasession2.command.extra"; = "android.media.media_session2.command.extra"; private final int mCommandCode; // Nonnull if it's custom command Loading Loading @@ -482,11 +482,180 @@ public class MediaSession2 extends MediaPlayerBase { @Override public String toString() { // TODO(jaewan): Move this to updatable. return "ControllerInfo {pkg=" + getPackageName() + ", uid=" + getUid() + ", trusted=" + isTrusted() + "}"; } } /** * Button for a {@link Command} that will be shown by the controller. * <p> * It's up to the controller's decision to respect or ignore this customization request. */ // TODO(jaewan): Move this to updatable. public static class CommandButton { private static final String KEY_COMMAND = "android.media.media_session2.command_button.command"; private static final String KEY_ICON_RES_ID = "android.media.media_session2.command_button.icon_res_id"; private static final String KEY_DISPLAY_NAME = "android.media.media_session2.command_button.display_name"; private static final String KEY_EXTRA = "android.media.media_session2.command_button.extra"; private static final String KEY_ENABLED = "android.media.media_session2.command_button.enabled"; private Command mCommand; private int mIconResId; private String mDisplayName; private Bundle mExtra; private boolean mEnabled; private CommandButton(@Nullable Command command, int iconResId, @Nullable String displayName, Bundle extra, boolean enabled) { mCommand = command; mIconResId = iconResId; mDisplayName = displayName; mExtra = extra; mEnabled = enabled; } /** * Get command associated with this button. Can be {@code null} if the button isn't enabled * and only providing placeholder. * * @return command or {@code null} */ public @Nullable Command getCommand() { return mCommand; } /** * Resource id of the button in this package. Can be {@code 0} if the command is predefined * and custom icon isn't needed. * * @return resource id of the icon. Can be {@code 0}. */ public int getIconResId() { return mIconResId; } /** * Display name of the button. Can be {@code null} or empty if the command is predefined * and custom name isn't needed. * * @return custom display name. Can be {@code null} or empty. */ public @Nullable String getDisplayName() { return mDisplayName; } /** * Extra information of the button. It's private information between session and controller. * * @return */ public @Nullable Bundle getExtra() { return mExtra; } /** * Return whether it's enabled * * @return {@code true} if enabled. {@code false} otherwise. */ public boolean isEnabled() { return mEnabled; } /** * @hide */ // TODO(jaewan): @SystemApi public @NonNull Bundle toBundle() { Bundle bundle = new Bundle(); bundle.putBundle(KEY_COMMAND, mCommand.toBundle()); bundle.putInt(KEY_ICON_RES_ID, mIconResId); bundle.putString(KEY_DISPLAY_NAME, mDisplayName); bundle.putBundle(KEY_EXTRA, mExtra); bundle.putBoolean(KEY_ENABLED, mEnabled); return bundle; } /** * @hide */ // TODO(jaewan): @SystemApi public static @Nullable CommandButton fromBundle(Bundle bundle) { Builder builder = new Builder(); builder.setCommand(Command.fromBundle(bundle.getBundle(KEY_COMMAND))); builder.setIconResId(bundle.getInt(KEY_ICON_RES_ID, 0)); builder.setDisplayName(bundle.getString(KEY_DISPLAY_NAME)); builder.setExtra(bundle.getBundle(KEY_EXTRA)); builder.setEnabled(bundle.getBoolean(KEY_ENABLED)); try { return builder.build(); } catch (IllegalStateException e) { // Malformed or version mismatch. Return null for now. return null; } } /** * Builder for {@link CommandButton}. */ public static class Builder { private Command mCommand; private int mIconResId; private String mDisplayName; private Bundle mExtra; private boolean mEnabled; public Builder() { mEnabled = true; } public Builder setCommand(Command command) { mCommand = command; return this; } public Builder setIconResId(int resId) { mIconResId = resId; return this; } public Builder setDisplayName(String displayName) { mDisplayName = displayName; return this; } public Builder setEnabled(boolean enabled) { mEnabled = enabled; return this; } public Builder setExtra(Bundle extra) { mExtra = extra; return this; } public CommandButton build() { if (mEnabled && mCommand == null) { throw new IllegalStateException("Enabled button needs Command" + " for controller to invoke the command"); } if (mCommand != null && mCommand.getCommandCode() == COMMAND_CODE_CUSTOM && (mIconResId == 0 || TextUtils.isEmpty(mDisplayName))) { throw new IllegalStateException("Custom commands needs icon and" + " and name to display"); } return new CommandButton(mCommand, mIconResId, mDisplayName, mExtra, mEnabled); } } } /** * Constructor is hidden and apps can only instantiate indirectly through {@link Builder}. * <p> Loading Loading @@ -556,6 +725,30 @@ public class MediaSession2 extends MediaPlayerBase { return mProvider.getConnectedControllers_impl(); } /** * Sets ordered list of {@link CommandButton} for controllers to build UI with it. * <p> * It's up to controller's decision how to represent the layout in its own UI. * Here's the same way * (layout[i] means a CommandButton at index i in the given list) * For 5 icons row * layout[3] layout[1] layout[0] layout[2] layout[4] * For 3 icons row * layout[1] layout[0] layout[2] * For 5 icons row with overflow icon (can show +5 extra buttons with overflow button) * expanded row: layout[5] layout[6] layout[7] layout[8] layout[9] * main row: layout[3] layout[1] layout[0] layout[2] layout[4] * <p> * This API can be called in the {@link SessionCallback#onConnect(ControllerInfo)}. * * @param controller controller to specify layout. * @param layout oredered list of layout. */ public void setCustomLayout(@NonNull ControllerInfo controller, @NonNull List<CommandButton> layout) { mProvider.setCustomLayout_impl(controller, layout); } @Override public void play() { mProvider.play_impl(); Loading media/java/android/media/update/MediaSession2Provider.java +2 −0 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package android.media.update; import android.media.MediaPlayerBase; import android.media.MediaSession2.CommandButton; import android.media.MediaSession2.ControllerInfo; import android.media.SessionToken; Loading @@ -30,6 +31,7 @@ public interface MediaSession2Provider extends MediaPlayerBaseProvider { MediaPlayerBase getPlayer_impl(); SessionToken getToken_impl(); List<ControllerInfo> getConnectedControllers_impl(); void setCustomLayout_impl(ControllerInfo controller, List<CommandButton> layout); /** * @hide Loading Loading
media/java/android/media/IMediaSession2Callback.aidl +2 −0 Original line number Diff line number Diff line Loading @@ -45,6 +45,8 @@ oneway interface IMediaSession2Callback { // TODO(jaewan): Is term 'accepted/rejected' correct? For permission, 'grant' is used. void onConnectionChanged(IMediaSession2 sessionBinder, in Bundle commandGroup); void onCustomLayoutChanged(in List<Bundle> commandButtonlist); ////////////////////////////////////////////////////////////////////////////////////////////// // Browser sepcific ////////////////////////////////////////////////////////////////////////////////////////////// Loading
media/java/android/media/MediaController2.java +13 −0 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ package android.media; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; import android.media.MediaSession2.CommandButton; import android.media.MediaSession2.CommandGroup; import android.media.MediaSession2.ControllerInfo; import android.media.session.MediaSessionManager; Loading @@ -26,6 +27,8 @@ import android.media.session.PlaybackState; import android.media.update.ApiLoader; import android.media.update.MediaController2Provider; import android.os.Handler; import java.util.List; import java.util.concurrent.Executor; /** Loading Loading @@ -81,6 +84,16 @@ public class MediaController2 extends MediaPlayerBase { * You don't need to call {@link #release()} after this. */ public void onDisconnected() { } /** * Called when the session sets the custom layout through the * {@link MediaSession2#setCustomLayout(ControllerInfo, List)}. * <p> * Can be called before {@link #onConnected(CommandGroup)} is called. * * @param layout */ public void onCustomLayoutChanged(List<CommandButton> layout) { } } private final MediaController2Provider mProvider; Loading
media/java/android/media/MediaSession2.java +196 −3 Original line number Diff line number Diff line Loading @@ -95,11 +95,11 @@ public class MediaSession2 extends MediaPlayerBase { // TODO(jaewan): Move this into the updatable. public static final class Command { private static final String KEY_COMMAND_CODE = "android.media.mediasession2.command.command_command"; = "android.media.media_session2.command.command_code"; private static final String KEY_COMMAND_CUSTOM_COMMAND = "android.media.mediasession2.command.custom_command"; = "android.media.media_session2.command.custom_command"; private static final String KEY_COMMAND_EXTRA = "android.media.mediasession2.command.extra"; = "android.media.media_session2.command.extra"; private final int mCommandCode; // Nonnull if it's custom command Loading Loading @@ -482,11 +482,180 @@ public class MediaSession2 extends MediaPlayerBase { @Override public String toString() { // TODO(jaewan): Move this to updatable. return "ControllerInfo {pkg=" + getPackageName() + ", uid=" + getUid() + ", trusted=" + isTrusted() + "}"; } } /** * Button for a {@link Command} that will be shown by the controller. * <p> * It's up to the controller's decision to respect or ignore this customization request. */ // TODO(jaewan): Move this to updatable. public static class CommandButton { private static final String KEY_COMMAND = "android.media.media_session2.command_button.command"; private static final String KEY_ICON_RES_ID = "android.media.media_session2.command_button.icon_res_id"; private static final String KEY_DISPLAY_NAME = "android.media.media_session2.command_button.display_name"; private static final String KEY_EXTRA = "android.media.media_session2.command_button.extra"; private static final String KEY_ENABLED = "android.media.media_session2.command_button.enabled"; private Command mCommand; private int mIconResId; private String mDisplayName; private Bundle mExtra; private boolean mEnabled; private CommandButton(@Nullable Command command, int iconResId, @Nullable String displayName, Bundle extra, boolean enabled) { mCommand = command; mIconResId = iconResId; mDisplayName = displayName; mExtra = extra; mEnabled = enabled; } /** * Get command associated with this button. Can be {@code null} if the button isn't enabled * and only providing placeholder. * * @return command or {@code null} */ public @Nullable Command getCommand() { return mCommand; } /** * Resource id of the button in this package. Can be {@code 0} if the command is predefined * and custom icon isn't needed. * * @return resource id of the icon. Can be {@code 0}. */ public int getIconResId() { return mIconResId; } /** * Display name of the button. Can be {@code null} or empty if the command is predefined * and custom name isn't needed. * * @return custom display name. Can be {@code null} or empty. */ public @Nullable String getDisplayName() { return mDisplayName; } /** * Extra information of the button. It's private information between session and controller. * * @return */ public @Nullable Bundle getExtra() { return mExtra; } /** * Return whether it's enabled * * @return {@code true} if enabled. {@code false} otherwise. */ public boolean isEnabled() { return mEnabled; } /** * @hide */ // TODO(jaewan): @SystemApi public @NonNull Bundle toBundle() { Bundle bundle = new Bundle(); bundle.putBundle(KEY_COMMAND, mCommand.toBundle()); bundle.putInt(KEY_ICON_RES_ID, mIconResId); bundle.putString(KEY_DISPLAY_NAME, mDisplayName); bundle.putBundle(KEY_EXTRA, mExtra); bundle.putBoolean(KEY_ENABLED, mEnabled); return bundle; } /** * @hide */ // TODO(jaewan): @SystemApi public static @Nullable CommandButton fromBundle(Bundle bundle) { Builder builder = new Builder(); builder.setCommand(Command.fromBundle(bundle.getBundle(KEY_COMMAND))); builder.setIconResId(bundle.getInt(KEY_ICON_RES_ID, 0)); builder.setDisplayName(bundle.getString(KEY_DISPLAY_NAME)); builder.setExtra(bundle.getBundle(KEY_EXTRA)); builder.setEnabled(bundle.getBoolean(KEY_ENABLED)); try { return builder.build(); } catch (IllegalStateException e) { // Malformed or version mismatch. Return null for now. return null; } } /** * Builder for {@link CommandButton}. */ public static class Builder { private Command mCommand; private int mIconResId; private String mDisplayName; private Bundle mExtra; private boolean mEnabled; public Builder() { mEnabled = true; } public Builder setCommand(Command command) { mCommand = command; return this; } public Builder setIconResId(int resId) { mIconResId = resId; return this; } public Builder setDisplayName(String displayName) { mDisplayName = displayName; return this; } public Builder setEnabled(boolean enabled) { mEnabled = enabled; return this; } public Builder setExtra(Bundle extra) { mExtra = extra; return this; } public CommandButton build() { if (mEnabled && mCommand == null) { throw new IllegalStateException("Enabled button needs Command" + " for controller to invoke the command"); } if (mCommand != null && mCommand.getCommandCode() == COMMAND_CODE_CUSTOM && (mIconResId == 0 || TextUtils.isEmpty(mDisplayName))) { throw new IllegalStateException("Custom commands needs icon and" + " and name to display"); } return new CommandButton(mCommand, mIconResId, mDisplayName, mExtra, mEnabled); } } } /** * Constructor is hidden and apps can only instantiate indirectly through {@link Builder}. * <p> Loading Loading @@ -556,6 +725,30 @@ public class MediaSession2 extends MediaPlayerBase { return mProvider.getConnectedControllers_impl(); } /** * Sets ordered list of {@link CommandButton} for controllers to build UI with it. * <p> * It's up to controller's decision how to represent the layout in its own UI. * Here's the same way * (layout[i] means a CommandButton at index i in the given list) * For 5 icons row * layout[3] layout[1] layout[0] layout[2] layout[4] * For 3 icons row * layout[1] layout[0] layout[2] * For 5 icons row with overflow icon (can show +5 extra buttons with overflow button) * expanded row: layout[5] layout[6] layout[7] layout[8] layout[9] * main row: layout[3] layout[1] layout[0] layout[2] layout[4] * <p> * This API can be called in the {@link SessionCallback#onConnect(ControllerInfo)}. * * @param controller controller to specify layout. * @param layout oredered list of layout. */ public void setCustomLayout(@NonNull ControllerInfo controller, @NonNull List<CommandButton> layout) { mProvider.setCustomLayout_impl(controller, layout); } @Override public void play() { mProvider.play_impl(); Loading
media/java/android/media/update/MediaSession2Provider.java +2 −0 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package android.media.update; import android.media.MediaPlayerBase; import android.media.MediaSession2.CommandButton; import android.media.MediaSession2.ControllerInfo; import android.media.SessionToken; Loading @@ -30,6 +31,7 @@ public interface MediaSession2Provider extends MediaPlayerBaseProvider { MediaPlayerBase getPlayer_impl(); SessionToken getToken_impl(); List<ControllerInfo> getConnectedControllers_impl(); void setCustomLayout_impl(ControllerInfo controller, List<CommandButton> layout); /** * @hide Loading