From c71e4bf1ffd4a0a0c631c27e4faa9480700e2c5f Mon Sep 17 00:00:00 2001 From: jbibik Date: Thu, 13 Apr 2023 13:28:33 +0100 Subject: [PATCH] Extend Player interface, overloading 4 device-volume methods with flags Previously, ExoPlayerImpl had volume flags hardcoded to SHOW_UI, but now the developer can choose what happens on volume change. The old methods have been deprecated. PiperOrigin-RevId: 523974358 --- RELEASENOTES.md | 6 + api.txt | 40 +++-- libraries/cast/build.gradle | 2 +- .../java/androidx/media3/cast/CastPlayer.java | 30 +++- .../main/java/androidx/media3/common/C.java | 31 ++++ .../media3/common/ForwardingPlayer.java | 44 +++++- .../java/androidx/media3/common/Player.java | 97 +++++++++--- .../media3/common/SimpleBasePlayer.java | 146 ++++++++++++++---- .../media3/common/SimpleBasePlayerTest.java | 80 ++++++---- .../exoplayer/StreamVolumeManagerTest.java | 38 +++-- .../media3/exoplayer/ExoPlayerImpl.java | 50 +++++- .../media3/exoplayer/SimpleExoPlayer.java | 40 +++++ .../media3/exoplayer/StreamVolumeManager.java | 45 +++--- .../media3/exoplayer/ExoPlayerTest.java | 12 +- .../media3/session/IMediaController.aidl | 1 - .../media3/session/IMediaSession.aidl | 7 +- .../media3/session/IMediaSessionService.aidl | 1 - .../media3/session/MediaController.java | 61 ++++++++ .../session/MediaControllerImplBase.java | 91 +++++++++++ .../session/MediaControllerImplLegacy.java | 51 +++++- .../media3/session/MediaSessionStub.java | 62 +++++++- .../androidx/media3/session/MediaUtils.java | 12 +- .../media3/session/PlayerWrapper.java | 95 ++++++++++-- .../common/IRemoteMediaController.aidl | 4 + .../session/common/IRemoteMediaSession.aidl | 9 +- ...lerCompatCallbackWithMediaSessionTest.java | 3 +- .../session/MediaControllerListenerTest.java | 15 +- .../MediaControllerStateMaskingTest.java | 12 +- ...CallbackWithMediaControllerCompatTest.java | 104 ++++++++++++- ...CompatCallbackWithMediaControllerTest.java | 19 ++- .../media3/session/MockPlayerTest.java | 41 +++++ .../MediaControllerProviderService.java | 52 ++++++- .../session/MediaSessionProviderService.java | 62 +++++--- .../androidx/media3/session/MockPlayer.java | 44 ++++++ .../media3/session/RemoteMediaController.java | 17 ++ .../media3/session/RemoteMediaSession.java | 33 ++-- .../media3/test/utils/StubPlayer.java | 37 +++++ 37 files changed, 1273 insertions(+), 221 deletions(-) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index dd0a0f3da1..fbc1e5e6f2 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -42,6 +42,12 @@ ([#293](https://github.com/androidx/media/issues/293)). * Fix bug where calling `MediaSession.setPlayer` doesn't update the available commands. + * Deprecate 4 volume-controlling methods in `Player` and add overloaded + methods which allow users to specify volume flags: + * `void setDeviceVolume(int, int)` + * `void increaseDeviceVolume(int)` + * `void decreaseDeviceVolume(int)` + * `void setDeviceMuted(boolean, int)` * Audio: * Fix bug where some playbacks fail when tunneling is enabled and `AudioProcessors` are active, e.g. for gapless trimming diff --git a/api.txt b/api.txt index 236f365c09..e7b3f4de74 100644 --- a/api.txt +++ b/api.txt @@ -127,6 +127,11 @@ package androidx.media3.common { field public static final int USAGE_VOICE_COMMUNICATION = 2; // 0x2 field public static final int USAGE_VOICE_COMMUNICATION_SIGNALLING = 3; // 0x3 field public static final java.util.UUID UUID_NIL; + field public static final int VOLUME_FLAG_ALLOW_RINGER_MODES = 2; // 0x2 + field public static final int VOLUME_FLAG_PLAY_SOUND = 4; // 0x4 + field public static final int VOLUME_FLAG_REMOVE_SOUND_AND_VIBRATE = 8; // 0x8 + field public static final int VOLUME_FLAG_SHOW_UI = 1; // 0x1 + field public static final int VOLUME_FLAG_VIBRATE = 16; // 0x10 field public static final int WAKE_MODE_LOCAL = 1; // 0x1 field public static final int WAKE_MODE_NETWORK = 2; // 0x2 field public static final int WAKE_MODE_NONE = 0; // 0x0 @@ -163,6 +168,9 @@ package androidx.media3.common { @IntDef(open=true, value={androidx.media3.common.C.TRACK_TYPE_UNKNOWN, androidx.media3.common.C.TRACK_TYPE_DEFAULT, androidx.media3.common.C.TRACK_TYPE_AUDIO, androidx.media3.common.C.TRACK_TYPE_VIDEO, androidx.media3.common.C.TRACK_TYPE_TEXT, androidx.media3.common.C.TRACK_TYPE_IMAGE, androidx.media3.common.C.TRACK_TYPE_METADATA, androidx.media3.common.C.TRACK_TYPE_CAMERA_MOTION, androidx.media3.common.C.TRACK_TYPE_NONE}) @java.lang.annotation.Documented @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) @java.lang.annotation.Target(java.lang.annotation.ElementType.TYPE_USE) public static @interface C.TrackType { } + @IntDef(flag=true, value={androidx.media3.common.C.VOLUME_FLAG_SHOW_UI, androidx.media3.common.C.VOLUME_FLAG_ALLOW_RINGER_MODES, androidx.media3.common.C.VOLUME_FLAG_PLAY_SOUND, androidx.media3.common.C.VOLUME_FLAG_REMOVE_SOUND_AND_VIBRATE, androidx.media3.common.C.VOLUME_FLAG_VIBRATE}) @java.lang.annotation.Documented @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) @java.lang.annotation.Target({java.lang.annotation.ElementType.TYPE_USE}) public static @interface C.VolumeFlags { + } + @IntDef({androidx.media3.common.C.WAKE_MODE_NONE, androidx.media3.common.C.WAKE_MODE_LOCAL, androidx.media3.common.C.WAKE_MODE_NETWORK}) @java.lang.annotation.Documented @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) @java.lang.annotation.Target({java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.METHOD, java.lang.annotation.ElementType.PARAMETER, java.lang.annotation.ElementType.LOCAL_VARIABLE, java.lang.annotation.ElementType.TYPE_USE}) public static @interface C.WakeMode { } @@ -666,7 +674,8 @@ package androidx.media3.common { method public void clearVideoSurfaceHolder(@Nullable android.view.SurfaceHolder); method public void clearVideoSurfaceView(@Nullable android.view.SurfaceView); method public void clearVideoTextureView(@Nullable android.view.TextureView); - method public void decreaseDeviceVolume(); + method @Deprecated public void decreaseDeviceVolume(); + method public void decreaseDeviceVolume(@androidx.media3.common.C.VolumeFlags int); method public android.os.Looper getApplicationLooper(); method public androidx.media3.common.AudioAttributes getAudioAttributes(); method public androidx.media3.common.Player.Commands getAvailableCommands(); @@ -710,7 +719,8 @@ package androidx.media3.common { method @FloatRange(from=0, to=1.0) public float getVolume(); method public boolean hasNextMediaItem(); method public boolean hasPreviousMediaItem(); - method public void increaseDeviceVolume(); + method @Deprecated public void increaseDeviceVolume(); + method public void increaseDeviceVolume(@androidx.media3.common.C.VolumeFlags int); method public boolean isCommandAvailable(@androidx.media3.common.Player.Command int); method public boolean isCurrentMediaItemDynamic(); method public boolean isCurrentMediaItemLive(); @@ -738,8 +748,10 @@ package androidx.media3.common { method public void seekToNextMediaItem(); method public void seekToPrevious(); method public void seekToPreviousMediaItem(); - method public void setDeviceMuted(boolean); - method public void setDeviceVolume(@IntRange(from=0) int); + method @Deprecated public void setDeviceMuted(boolean); + method public void setDeviceMuted(boolean, @androidx.media3.common.C.VolumeFlags int); + method @Deprecated public void setDeviceVolume(@IntRange(from=0) int); + method public void setDeviceVolume(@IntRange(from=0) int, int); method public void setMediaItem(androidx.media3.common.MediaItem); method public void setMediaItem(androidx.media3.common.MediaItem, long); method public void setMediaItem(androidx.media3.common.MediaItem, boolean); @@ -759,7 +771,8 @@ package androidx.media3.common { method public void setVideoTextureView(@Nullable android.view.TextureView); method public void setVolume(@FloatRange(from=0, to=1.0) float); method public void stop(); - field public static final int COMMAND_ADJUST_DEVICE_VOLUME = 26; // 0x1a + field @Deprecated public static final int COMMAND_ADJUST_DEVICE_VOLUME = 26; // 0x1a + field public static final int COMMAND_ADJUST_DEVICE_VOLUME_WITH_FLAGS = 34; // 0x22 field public static final int COMMAND_CHANGE_MEDIA_ITEMS = 20; // 0x14 field public static final int COMMAND_GET_AUDIO_ATTRIBUTES = 21; // 0x15 field public static final int COMMAND_GET_CURRENT_MEDIA_ITEM = 16; // 0x10 @@ -783,7 +796,8 @@ package androidx.media3.common { field public static final int COMMAND_SEEK_TO_NEXT_MEDIA_ITEM = 8; // 0x8 field public static final int COMMAND_SEEK_TO_PREVIOUS = 7; // 0x7 field public static final int COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM = 6; // 0x6 - field public static final int COMMAND_SET_DEVICE_VOLUME = 25; // 0x19 + field @Deprecated public static final int COMMAND_SET_DEVICE_VOLUME = 25; // 0x19 + field public static final int COMMAND_SET_DEVICE_VOLUME_WITH_FLAGS = 33; // 0x21 field public static final int COMMAND_SET_MEDIA_ITEM = 31; // 0x1f field @Deprecated public static final int COMMAND_SET_MEDIA_ITEMS_METADATA = 19; // 0x13 field public static final int COMMAND_SET_PLAYLIST_METADATA = 19; // 0x13 @@ -855,7 +869,7 @@ package androidx.media3.common { field public static final int TIMELINE_CHANGE_REASON_SOURCE_UPDATE = 1; // 0x1 } - @IntDef({androidx.media3.common.Player.COMMAND_INVALID, androidx.media3.common.Player.COMMAND_PLAY_PAUSE, androidx.media3.common.Player.COMMAND_PREPARE, androidx.media3.common.Player.COMMAND_STOP, androidx.media3.common.Player.COMMAND_SEEK_TO_DEFAULT_POSITION, androidx.media3.common.Player.COMMAND_SEEK_IN_CURRENT_MEDIA_ITEM, androidx.media3.common.Player.COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM, androidx.media3.common.Player.COMMAND_SEEK_TO_PREVIOUS, androidx.media3.common.Player.COMMAND_SEEK_TO_NEXT_MEDIA_ITEM, androidx.media3.common.Player.COMMAND_SEEK_TO_NEXT, androidx.media3.common.Player.COMMAND_SEEK_TO_MEDIA_ITEM, androidx.media3.common.Player.COMMAND_SEEK_BACK, androidx.media3.common.Player.COMMAND_SEEK_FORWARD, androidx.media3.common.Player.COMMAND_SET_SPEED_AND_PITCH, androidx.media3.common.Player.COMMAND_SET_SHUFFLE_MODE, androidx.media3.common.Player.COMMAND_SET_REPEAT_MODE, androidx.media3.common.Player.COMMAND_GET_CURRENT_MEDIA_ITEM, androidx.media3.common.Player.COMMAND_GET_TIMELINE, androidx.media3.common.Player.COMMAND_GET_MEDIA_ITEMS_METADATA, androidx.media3.common.Player.COMMAND_GET_METADATA, androidx.media3.common.Player.COMMAND_SET_MEDIA_ITEMS_METADATA, androidx.media3.common.Player.COMMAND_SET_PLAYLIST_METADATA, androidx.media3.common.Player.COMMAND_SET_MEDIA_ITEM, androidx.media3.common.Player.COMMAND_CHANGE_MEDIA_ITEMS, androidx.media3.common.Player.COMMAND_GET_AUDIO_ATTRIBUTES, androidx.media3.common.Player.COMMAND_GET_VOLUME, androidx.media3.common.Player.COMMAND_GET_DEVICE_VOLUME, androidx.media3.common.Player.COMMAND_SET_VOLUME, androidx.media3.common.Player.COMMAND_SET_DEVICE_VOLUME, androidx.media3.common.Player.COMMAND_ADJUST_DEVICE_VOLUME, androidx.media3.common.Player.COMMAND_SET_VIDEO_SURFACE, androidx.media3.common.Player.COMMAND_GET_TEXT, androidx.media3.common.Player.COMMAND_SET_TRACK_SELECTION_PARAMETERS, androidx.media3.common.Player.COMMAND_GET_TRACKS, androidx.media3.common.Player.COMMAND_RELEASE}) @java.lang.annotation.Documented @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) @java.lang.annotation.Target({java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.METHOD, java.lang.annotation.ElementType.PARAMETER, java.lang.annotation.ElementType.LOCAL_VARIABLE, java.lang.annotation.ElementType.TYPE_USE}) public static @interface Player.Command { + @IntDef({androidx.media3.common.Player.COMMAND_INVALID, androidx.media3.common.Player.COMMAND_PLAY_PAUSE, androidx.media3.common.Player.COMMAND_PREPARE, androidx.media3.common.Player.COMMAND_STOP, androidx.media3.common.Player.COMMAND_SEEK_TO_DEFAULT_POSITION, androidx.media3.common.Player.COMMAND_SEEK_IN_CURRENT_MEDIA_ITEM, androidx.media3.common.Player.COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM, androidx.media3.common.Player.COMMAND_SEEK_TO_PREVIOUS, androidx.media3.common.Player.COMMAND_SEEK_TO_NEXT_MEDIA_ITEM, androidx.media3.common.Player.COMMAND_SEEK_TO_NEXT, androidx.media3.common.Player.COMMAND_SEEK_TO_MEDIA_ITEM, androidx.media3.common.Player.COMMAND_SEEK_BACK, androidx.media3.common.Player.COMMAND_SEEK_FORWARD, androidx.media3.common.Player.COMMAND_SET_SPEED_AND_PITCH, androidx.media3.common.Player.COMMAND_SET_SHUFFLE_MODE, androidx.media3.common.Player.COMMAND_SET_REPEAT_MODE, androidx.media3.common.Player.COMMAND_GET_CURRENT_MEDIA_ITEM, androidx.media3.common.Player.COMMAND_GET_TIMELINE, androidx.media3.common.Player.COMMAND_GET_MEDIA_ITEMS_METADATA, androidx.media3.common.Player.COMMAND_GET_METADATA, androidx.media3.common.Player.COMMAND_SET_MEDIA_ITEMS_METADATA, androidx.media3.common.Player.COMMAND_SET_PLAYLIST_METADATA, androidx.media3.common.Player.COMMAND_SET_MEDIA_ITEM, androidx.media3.common.Player.COMMAND_CHANGE_MEDIA_ITEMS, androidx.media3.common.Player.COMMAND_GET_AUDIO_ATTRIBUTES, androidx.media3.common.Player.COMMAND_GET_VOLUME, androidx.media3.common.Player.COMMAND_GET_DEVICE_VOLUME, androidx.media3.common.Player.COMMAND_SET_VOLUME, androidx.media3.common.Player.COMMAND_SET_DEVICE_VOLUME, androidx.media3.common.Player.COMMAND_SET_DEVICE_VOLUME_WITH_FLAGS, androidx.media3.common.Player.COMMAND_ADJUST_DEVICE_VOLUME, androidx.media3.common.Player.COMMAND_ADJUST_DEVICE_VOLUME_WITH_FLAGS, androidx.media3.common.Player.COMMAND_SET_VIDEO_SURFACE, androidx.media3.common.Player.COMMAND_GET_TEXT, androidx.media3.common.Player.COMMAND_SET_TRACK_SELECTION_PARAMETERS, androidx.media3.common.Player.COMMAND_GET_TRACKS, androidx.media3.common.Player.COMMAND_RELEASE}) @java.lang.annotation.Documented @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) @java.lang.annotation.Target({java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.METHOD, java.lang.annotation.ElementType.PARAMETER, java.lang.annotation.ElementType.LOCAL_VARIABLE, java.lang.annotation.ElementType.TYPE_USE}) public static @interface Player.Command { } public static final class Player.Commands { @@ -1499,7 +1513,8 @@ package androidx.media3.session { method public final void clearVideoSurfaceHolder(@Nullable android.view.SurfaceHolder); method public final void clearVideoSurfaceView(@Nullable android.view.SurfaceView); method public final void clearVideoTextureView(@Nullable android.view.TextureView); - method public final void decreaseDeviceVolume(); + method @Deprecated public final void decreaseDeviceVolume(); + method public final void decreaseDeviceVolume(@androidx.media3.common.C.VolumeFlags int); method public final android.os.Looper getApplicationLooper(); method public final androidx.media3.common.AudioAttributes getAudioAttributes(); method public final androidx.media3.common.Player.Commands getAvailableCommands(); @@ -1546,7 +1561,8 @@ package androidx.media3.session { method @FloatRange(from=0, to=1) public final float getVolume(); method public final boolean hasNextMediaItem(); method public final boolean hasPreviousMediaItem(); - method public final void increaseDeviceVolume(); + method @Deprecated public final void increaseDeviceVolume(); + method public final void increaseDeviceVolume(@androidx.media3.common.C.VolumeFlags int); method public final boolean isCommandAvailable(@androidx.media3.common.Player.Command int); method public final boolean isConnected(); method public final boolean isCurrentMediaItemDynamic(); @@ -1579,8 +1595,10 @@ package androidx.media3.session { method public final void seekToPrevious(); method public final void seekToPreviousMediaItem(); method public final com.google.common.util.concurrent.ListenableFuture sendCustomCommand(androidx.media3.session.SessionCommand, android.os.Bundle); - method public final void setDeviceMuted(boolean); - method public final void setDeviceVolume(@IntRange(from=0) int); + method @Deprecated public final void setDeviceMuted(boolean); + method public final void setDeviceMuted(boolean, @androidx.media3.common.C.VolumeFlags int); + method @Deprecated public final void setDeviceVolume(@IntRange(from=0) int); + method public final void setDeviceVolume(@IntRange(from=0) int, @androidx.media3.common.C.VolumeFlags int); method public final void setMediaItem(androidx.media3.common.MediaItem); method public final void setMediaItem(androidx.media3.common.MediaItem, long); method public final void setMediaItem(androidx.media3.common.MediaItem, boolean); diff --git a/libraries/cast/build.gradle b/libraries/cast/build.gradle index 87f7e6f20c..e22afd8dc7 100644 --- a/libraries/cast/build.gradle +++ b/libraries/cast/build.gradle @@ -14,7 +14,7 @@ apply from: "$gradle.ext.androidxMediaSettingsDir/common_library_config.gradle" dependencies { - api 'com.google.android.gms:play-services-cast-framework:21.2.0' + api 'com.google.android.gms:play-services-cast-framework:21.3.0' implementation 'androidx.annotation:annotation:' + androidxAnnotationVersion implementation project(modulePrefix + 'lib-common') compileOnly 'org.checkerframework:checker-qual:' + checkerframeworkVersion diff --git a/libraries/cast/src/main/java/androidx/media3/cast/CastPlayer.java b/libraries/cast/src/main/java/androidx/media3/cast/CastPlayer.java index 80a549c0de..f699f6f070 100644 --- a/libraries/cast/src/main/java/androidx/media3/cast/CastPlayer.java +++ b/libraries/cast/src/main/java/androidx/media3/cast/CastPlayer.java @@ -755,22 +755,50 @@ public final class CastPlayer extends BasePlayer { return false; } - /** This method is not supported and does nothing. */ + /** + * @deprecated Use {@link #setDeviceVolume(int, int)} instead. + */ + @Deprecated @Override public void setDeviceVolume(int volume) {} /** This method is not supported and does nothing. */ @Override + public void setDeviceVolume(int volume, @C.VolumeFlags int flags) {} + + /** + * @deprecated Use {@link #increaseDeviceVolume(int)} instead. + */ + @Deprecated + @Override public void increaseDeviceVolume() {} /** This method is not supported and does nothing. */ @Override + public void increaseDeviceVolume(@C.VolumeFlags int flags) {} + + /** + * @deprecated Use {@link #decreaseDeviceVolume(int)} instead. + */ + @Deprecated + @Override public void decreaseDeviceVolume() {} /** This method is not supported and does nothing. */ @Override + public void decreaseDeviceVolume(@C.VolumeFlags int flags) {} + + /** + * @deprecated Use {@link #setDeviceMuted(boolean, int)} instead. + */ + @Deprecated + @Override public void setDeviceMuted(boolean muted) {} + /** This method is not supported and does nothing. */ + @Override + public void setDeviceMuted(boolean muted, @C.VolumeFlags int flags) {} + // Internal methods. // Call deprecated callbacks. diff --git a/libraries/common/src/main/java/androidx/media3/common/C.java b/libraries/common/src/main/java/androidx/media3/common/C.java index a9364dba83..2689b19bc4 100644 --- a/libraries/common/src/main/java/androidx/media3/common/C.java +++ b/libraries/common/src/main/java/androidx/media3/common/C.java @@ -409,6 +409,37 @@ public final class C { /** The default stream type used by audio renderers. Equal to {@link #STREAM_TYPE_MUSIC}. */ @UnstableApi public static final int STREAM_TYPE_DEFAULT = STREAM_TYPE_MUSIC; + /** + * Volume flags to be used when setting or adjusting device volume. The value can be either 0 or a + * combination of the following flags: {@link #VOLUME_FLAG_SHOW_UI}, {@link + * #VOLUME_FLAG_ALLOW_RINGER_MODES}, {@link #VOLUME_FLAG_PLAY_SOUND}, {@link + * #VOLUME_FLAG_REMOVE_SOUND_AND_VIBRATE}, {@link #VOLUME_FLAG_VIBRATE}. + */ + @Documented + @Retention(RetentionPolicy.SOURCE) + @Target({TYPE_USE}) + @IntDef( + flag = true, + value = { + VOLUME_FLAG_SHOW_UI, + VOLUME_FLAG_ALLOW_RINGER_MODES, + VOLUME_FLAG_PLAY_SOUND, + VOLUME_FLAG_REMOVE_SOUND_AND_VIBRATE, + VOLUME_FLAG_VIBRATE, + }) + public @interface VolumeFlags {} + /** See {@link AudioManager#FLAG_SHOW_UI}. */ + public static final int VOLUME_FLAG_SHOW_UI = AudioManager.FLAG_SHOW_UI; + /** See {@link AudioManager#FLAG_ALLOW_RINGER_MODES}. */ + public static final int VOLUME_FLAG_ALLOW_RINGER_MODES = AudioManager.FLAG_ALLOW_RINGER_MODES; + /** See {@link AudioManager#FLAG_PLAY_SOUND}. */ + public static final int VOLUME_FLAG_PLAY_SOUND = AudioManager.FLAG_PLAY_SOUND; + /** See {@link AudioManager#FLAG_REMOVE_SOUND_AND_VIBRATE}. */ + public static final int VOLUME_FLAG_REMOVE_SOUND_AND_VIBRATE = + AudioManager.FLAG_REMOVE_SOUND_AND_VIBRATE; + /** See {@link AudioManager#FLAG_VIBRATE}. */ + public static final int VOLUME_FLAG_VIBRATE = AudioManager.FLAG_VIBRATE; + /** * Content types for audio attributes. One of: * diff --git a/libraries/common/src/main/java/androidx/media3/common/ForwardingPlayer.java b/libraries/common/src/main/java/androidx/media3/common/ForwardingPlayer.java index a1f5c79e98..9695c998b7 100644 --- a/libraries/common/src/main/java/androidx/media3/common/ForwardingPlayer.java +++ b/libraries/common/src/main/java/androidx/media3/common/ForwardingPlayer.java @@ -846,30 +846,66 @@ public class ForwardingPlayer implements Player { return player.isDeviceMuted(); } - /** Calls {@link Player#setDeviceVolume(int)} on the delegate. */ + /** + * @deprecated Use {@link #setDeviceVolume(int, int)} instead. + */ + @Deprecated @Override public void setDeviceVolume(int volume) { player.setDeviceVolume(volume); } - /** Calls {@link Player#increaseDeviceVolume()} on the delegate. */ + /** Calls {@link Player#setDeviceVolume(int, int)} on the delegate. */ + @Override + public void setDeviceVolume(int volume, @C.VolumeFlags int flags) { + player.setDeviceVolume(volume, flags); + } + + /** + * @deprecated Use {@link #increaseDeviceVolume(int)} instead. + */ + @Deprecated @Override public void increaseDeviceVolume() { player.increaseDeviceVolume(); } - /** Calls {@link Player#decreaseDeviceVolume()} on the delegate. */ + /** Calls {@link Player#increaseDeviceVolume(int)} on the delegate. */ + @Override + public void increaseDeviceVolume(@C.VolumeFlags int flags) { + player.increaseDeviceVolume(flags); + } + + /** + * @deprecated Use {@link #decreaseDeviceVolume(int)} instead. + */ + @Deprecated @Override public void decreaseDeviceVolume() { player.decreaseDeviceVolume(); } - /** Calls {@link Player#setDeviceMuted(boolean)} on the delegate. */ + /** Calls {@link Player#decreaseDeviceVolume(int)} on the delegate. */ + @Override + public void decreaseDeviceVolume(@C.VolumeFlags int flags) { + player.decreaseDeviceVolume(flags); + } + + /** + * @deprecated Use {@link #setDeviceMuted(boolean, int)} instead. + */ + @Deprecated @Override public void setDeviceMuted(boolean muted) { player.setDeviceMuted(muted); } + /** Calls {@link Player#setDeviceMuted(boolean, int)} on the delegate. */ + @Override + public void setDeviceMuted(boolean muted, @C.VolumeFlags int flags) { + player.setDeviceMuted(muted, flags); + } + /** Returns the {@link Player} to which operations are forwarded. */ public Player getWrappedPlayer() { return player; diff --git a/libraries/common/src/main/java/androidx/media3/common/Player.java b/libraries/common/src/main/java/androidx/media3/common/Player.java index 1a4f4f5cce..f9766a2fb7 100644 --- a/libraries/common/src/main/java/androidx/media3/common/Player.java +++ b/libraries/common/src/main/java/androidx/media3/common/Player.java @@ -380,7 +380,9 @@ public interface Player { COMMAND_GET_DEVICE_VOLUME, COMMAND_SET_VOLUME, COMMAND_SET_DEVICE_VOLUME, + COMMAND_SET_DEVICE_VOLUME_WITH_FLAGS, COMMAND_ADJUST_DEVICE_VOLUME, + COMMAND_ADJUST_DEVICE_VOLUME_WITH_FLAGS, COMMAND_SET_VIDEO_SURFACE, COMMAND_GET_TEXT, COMMAND_SET_TRACK_SELECTION_PARAMETERS, @@ -1437,7 +1439,9 @@ public interface Player { *
  • {@link #COMMAND_GET_DEVICE_VOLUME} *
  • {@link #COMMAND_SET_VOLUME} *
  • {@link #COMMAND_SET_DEVICE_VOLUME} + *
  • {@link #COMMAND_SET_DEVICE_VOLUME_WITH_FLAGS} *
  • {@link #COMMAND_ADJUST_DEVICE_VOLUME} + *
  • {@link #COMMAND_ADJUST_DEVICE_VOLUME_WITH_FLAGS} *
  • {@link #COMMAND_SET_VIDEO_SURFACE} *
  • {@link #COMMAND_GET_TEXT} *
  • {@link #COMMAND_SET_TRACK_SELECTION_PARAMETERS} @@ -1481,7 +1485,9 @@ public interface Player { COMMAND_GET_DEVICE_VOLUME, COMMAND_SET_VOLUME, COMMAND_SET_DEVICE_VOLUME, + COMMAND_SET_DEVICE_VOLUME_WITH_FLAGS, COMMAND_ADJUST_DEVICE_VOLUME, + COMMAND_ADJUST_DEVICE_VOLUME_WITH_FLAGS, COMMAND_SET_VIDEO_SURFACE, COMMAND_GET_TEXT, COMMAND_SET_TRACK_SELECTION_PARAMETERS, @@ -1788,27 +1794,36 @@ public interface Player { * #isCommandAvailable(int) available}. */ int COMMAND_SET_VOLUME = 24; - /** - * Command to set the device volume. - * - *

    The {@link #setDeviceVolume(int)} method must only be called if this command is {@linkplain - * #isCommandAvailable(int) available}. - */ - int COMMAND_SET_DEVICE_VOLUME = 25; /** - * Command to increase and decrease the device volume and mute it. + * @deprecated Use {@link #COMMAND_SET_DEVICE_VOLUME_WITH_FLAGS} instead. + */ + @Deprecated int COMMAND_SET_DEVICE_VOLUME = 25; + /** + * Command to set the device volume with volume flags. + * + *

    The {@link #setDeviceVolume(int, int)} method must only be called if this command is + * {@linkplain #isCommandAvailable(int) available}. + */ + int COMMAND_SET_DEVICE_VOLUME_WITH_FLAGS = 33; + + /** + * @deprecated Use {@link #COMMAND_ADJUST_DEVICE_VOLUME_WITH_FLAGS} instead. + */ + @Deprecated int COMMAND_ADJUST_DEVICE_VOLUME = 26; + /** + * Command to increase and decrease the device volume and mute it with volume flags. * *

    The following methods must only be called if this command is {@linkplain * #isCommandAvailable(int) available}: * *

      - *
    • {@link #increaseDeviceVolume()} - *
    • {@link #decreaseDeviceVolume()} - *
    • {@link #setDeviceMuted(boolean)} + *
    • {@link #increaseDeviceVolume(int)} + *
    • {@link #decreaseDeviceVolume(int)} + *
    • {@link #setDeviceMuted(boolean, int)} *
    */ - int COMMAND_ADJUST_DEVICE_VOLUME = 26; + int COMMAND_ADJUST_DEVICE_VOLUME_WITH_FLAGS = 34; /** * Command to set and clear the surface on which to render the video. @@ -3095,36 +3110,68 @@ public interface Player { boolean isDeviceMuted(); /** - * Sets the volume of the device. + * @deprecated Use {@link #setDeviceVolume(int, int)} instead. + */ + @Deprecated + void setDeviceVolume(@IntRange(from = 0) int volume); + + /** + * Sets the volume of the device with volume flags. * - *

    This method must only be called if {@link #COMMAND_SET_DEVICE_VOLUME} is {@linkplain - * #getAvailableCommands() available}. + *

    This method must only be called if {@link #COMMAND_SET_DEVICE_VOLUME_WITH_FLAGS} is + * {@linkplain #getAvailableCommands() available}. * * @param volume The volume to set. + * @param flags Either 0 or a bitwise combination of one or more {@link C.VolumeFlags}. */ - void setDeviceVolume(@IntRange(from = 0) int volume); + void setDeviceVolume(@IntRange(from = 0) int volume, int flags); + + /** + * @deprecated Use {@link #increaseDeviceVolume(int)} instead. + */ + @Deprecated + void increaseDeviceVolume(); /** * Increases the volume of the device. * - *

    This method must only be called if {@link #COMMAND_ADJUST_DEVICE_VOLUME} is {@linkplain - * #getAvailableCommands() available}. + *

    This method must only be called if {@link #COMMAND_ADJUST_DEVICE_VOLUME_WITH_FLAGS} is + * {@linkplain #getAvailableCommands() available}. + * + * @param flags Either 0 or a bitwise combination of one or more {@link C.VolumeFlags}. */ - void increaseDeviceVolume(); + void increaseDeviceVolume(@C.VolumeFlags int flags); + + /** + * @deprecated Use {@link #decreaseDeviceVolume(int)} instead. + */ + @Deprecated + void decreaseDeviceVolume(); /** * Decreases the volume of the device. * - *

    This method must only be called if {@link #COMMAND_ADJUST_DEVICE_VOLUME} is {@linkplain - * #getAvailableCommands() available}. + *

    This method must only be called if {@link #COMMAND_ADJUST_DEVICE_VOLUME_WITH_FLAGS} is + * {@linkplain #getAvailableCommands() available}. + * + * @param flags Either 0 or a bitwise combination of one or more {@link C.VolumeFlags}. */ - void decreaseDeviceVolume(); + void decreaseDeviceVolume(@C.VolumeFlags int flags); + + /** + * @deprecated Use {@link #setDeviceMuted(boolean, int)} instead. + */ + @Deprecated + void setDeviceMuted(boolean muted); /** * Sets the mute state of the device. * - *

    This method must only be called if {@link #COMMAND_ADJUST_DEVICE_VOLUME} is {@linkplain - * #getAvailableCommands() available}. + *

    This method must only be called if {@link #COMMAND_ADJUST_DEVICE_VOLUME_WITH_FLAGS} is + * {@linkplain #getAvailableCommands() available}. + * + * @param muted Whether to set the device to be muted or not + * @param flags Either 0 or a bitwise combination of one or more {@link C.VolumeFlags}. */ - void setDeviceMuted(boolean muted); + void setDeviceMuted(boolean muted, @C.VolumeFlags int flags); } diff --git a/libraries/common/src/main/java/androidx/media3/common/SimpleBasePlayer.java b/libraries/common/src/main/java/androidx/media3/common/SimpleBasePlayer.java index 9ecb623582..3411a41b69 100644 --- a/libraries/common/src/main/java/androidx/media3/common/SimpleBasePlayer.java +++ b/libraries/common/src/main/java/androidx/media3/common/SimpleBasePlayer.java @@ -2661,6 +2661,10 @@ public abstract class SimpleBasePlayer extends BasePlayer { return state.isDeviceMuted; } + /** + * @deprecated Use {@link #setDeviceVolume(int, int)} instead. + */ + @Deprecated @Override public final void setDeviceVolume(int volume) { verifyApplicationThreadAndInitState(); @@ -2670,10 +2674,27 @@ public abstract class SimpleBasePlayer extends BasePlayer { return; } updateStateForPendingOperation( - /* pendingOperation= */ handleSetDeviceVolume(volume), + /* pendingOperation= */ handleSetDeviceVolume(volume, C.VOLUME_FLAG_SHOW_UI), /* placeholderStateSupplier= */ () -> state.buildUpon().setDeviceVolume(volume).build()); } + @Override + public final void setDeviceVolume(int volume, @C.VolumeFlags int flags) { + verifyApplicationThreadAndInitState(); + // Use a local copy to ensure the lambda below uses the current state value. + State state = this.state; + if (!shouldHandleCommand(Player.COMMAND_SET_DEVICE_VOLUME_WITH_FLAGS)) { + return; + } + updateStateForPendingOperation( + /* pendingOperation= */ handleSetDeviceVolume(volume, flags), + /* placeholderStateSupplier= */ () -> state.buildUpon().setDeviceVolume(volume).build()); + } + + /** + * @deprecated Use {@link #increaseDeviceVolume(int)} instead. + */ + @Deprecated @Override public final void increaseDeviceVolume() { verifyApplicationThreadAndInitState(); @@ -2683,11 +2704,29 @@ public abstract class SimpleBasePlayer extends BasePlayer { return; } updateStateForPendingOperation( - /* pendingOperation= */ handleIncreaseDeviceVolume(), + /* pendingOperation= */ handleIncreaseDeviceVolume(C.VOLUME_FLAG_SHOW_UI), /* placeholderStateSupplier= */ () -> state.buildUpon().setDeviceVolume(state.deviceVolume + 1).build()); } + @Override + public final void increaseDeviceVolume(@C.VolumeFlags int flags) { + verifyApplicationThreadAndInitState(); + // Use a local copy to ensure the lambda below uses the current state value. + State state = this.state; + if (!shouldHandleCommand(Player.COMMAND_ADJUST_DEVICE_VOLUME_WITH_FLAGS)) { + return; + } + updateStateForPendingOperation( + /* pendingOperation= */ handleIncreaseDeviceVolume(flags), + /* placeholderStateSupplier= */ () -> + state.buildUpon().setDeviceVolume(state.deviceVolume + 1).build()); + } + + /** + * @deprecated Use {@link #decreaseDeviceVolume(int)} instead. + */ + @Deprecated @Override public final void decreaseDeviceVolume() { verifyApplicationThreadAndInitState(); @@ -2697,11 +2736,29 @@ public abstract class SimpleBasePlayer extends BasePlayer { return; } updateStateForPendingOperation( - /* pendingOperation= */ handleDecreaseDeviceVolume(), + /* pendingOperation= */ handleDecreaseDeviceVolume(C.VOLUME_FLAG_SHOW_UI), /* placeholderStateSupplier= */ () -> state.buildUpon().setDeviceVolume(max(0, state.deviceVolume - 1)).build()); } + @Override + public final void decreaseDeviceVolume(@C.VolumeFlags int flags) { + verifyApplicationThreadAndInitState(); + // Use a local copy to ensure the lambda below uses the current state value. + State state = this.state; + if (!shouldHandleCommand(Player.COMMAND_ADJUST_DEVICE_VOLUME_WITH_FLAGS)) { + return; + } + updateStateForPendingOperation( + /* pendingOperation= */ handleDecreaseDeviceVolume(flags), + /* placeholderStateSupplier= */ () -> + state.buildUpon().setDeviceVolume(max(0, state.deviceVolume - 1)).build()); + } + + /** + * @deprecated Use {@link #setDeviceMuted(boolean, int)} instead. + */ + @Deprecated @Override public final void setDeviceMuted(boolean muted) { verifyApplicationThreadAndInitState(); @@ -2711,7 +2768,20 @@ public abstract class SimpleBasePlayer extends BasePlayer { return; } updateStateForPendingOperation( - /* pendingOperation= */ handleSetDeviceMuted(muted), + /* pendingOperation= */ handleSetDeviceMuted(muted, C.VOLUME_FLAG_SHOW_UI), + /* placeholderStateSupplier= */ () -> state.buildUpon().setIsDeviceMuted(muted).build()); + } + + @Override + public final void setDeviceMuted(boolean muted, @C.VolumeFlags int flags) { + verifyApplicationThreadAndInitState(); + // Use a local copy to ensure the lambda below uses the current state value. + State state = this.state; + if (!shouldHandleCommand(Player.COMMAND_ADJUST_DEVICE_VOLUME_WITH_FLAGS)) { + return; + } + updateStateForPendingOperation( + /* pendingOperation= */ handleSetDeviceMuted(muted, flags), /* placeholderStateSupplier= */ () -> state.buildUpon().setIsDeviceMuted(muted).build()); } @@ -2928,60 +2998,78 @@ public abstract class SimpleBasePlayer extends BasePlayer { } /** - * Handles calls to {@link Player#setDeviceVolume}. + * Handles calls to {@link Player#setDeviceVolume(int)} and {@link Player#setDeviceVolume(int, + * int)}. * - *

    Will only be called if {@link Player#COMMAND_SET_DEVICE_VOLUME} is available. + *

    Will only be called if {@link Player#COMMAND_SET_DEVICE_VOLUME} or {@link + * Player#COMMAND_SET_DEVICE_VOLUME_WITH_FLAGS} is available. * * @param deviceVolume The requested device volume. + * @param flags Either 0 or a bitwise combination of one or more {@link C.VolumeFlags}. * @return A {@link ListenableFuture} indicating the completion of all immediate {@link State} * changes caused by this call. */ @ForOverride - protected ListenableFuture handleSetDeviceVolume(@IntRange(from = 0) int deviceVolume) { - throw new IllegalStateException("Missing implementation to handle COMMAND_SET_DEVICE_VOLUME"); - } - - /** - * Handles calls to {@link Player#increaseDeviceVolume()}. - * - *

    Will only be called if {@link Player#COMMAND_ADJUST_DEVICE_VOLUME} is available. - * - * @return A {@link ListenableFuture} indicating the completion of all immediate {@link State} - * changes caused by this call. - */ - @ForOverride - protected ListenableFuture handleIncreaseDeviceVolume() { + protected ListenableFuture handleSetDeviceVolume( + @IntRange(from = 0) int deviceVolume, int flags) { throw new IllegalStateException( - "Missing implementation to handle COMMAND_ADJUST_DEVICE_VOLUME"); + "Missing implementation to handle COMMAND_SET_DEVICE_VOLUME or" + + " COMMAND_SET_DEVICE_VOLUME_WITH_FLAGS"); } /** - * Handles calls to {@link Player#decreaseDeviceVolume()}. + * Handles calls to {@link Player#increaseDeviceVolume()} and {@link + * Player#increaseDeviceVolume(int)}. * - *

    Will only be called if {@link Player#COMMAND_ADJUST_DEVICE_VOLUME} is available. + *

    Will only be called if {@link Player#COMMAND_ADJUST_DEVICE_VOLUME} or {@link + * Player#COMMAND_ADJUST_DEVICE_VOLUME_WITH_FLAGS} is available. * + * @param flags Either 0 or a bitwise combination of one or more {@link C.VolumeFlags}. * @return A {@link ListenableFuture} indicating the completion of all immediate {@link State} * changes caused by this call. */ @ForOverride - protected ListenableFuture handleDecreaseDeviceVolume() { + protected ListenableFuture handleIncreaseDeviceVolume(@C.VolumeFlags int flags) { throw new IllegalStateException( - "Missing implementation to handle COMMAND_ADJUST_DEVICE_VOLUME"); + "Missing implementation to handle COMMAND_ADJUST_DEVICE_VOLUME or" + + " COMMAND_ADJUST_DEVICE_VOLUME_WITH_FLAGS"); } /** - * Handles calls to {@link Player#setDeviceMuted}. + * Handles calls to {@link Player#decreaseDeviceVolume()} and {@link + * Player#decreaseDeviceVolume(int)}. * - *

    Will only be called if {@link Player#COMMAND_ADJUST_DEVICE_VOLUME} is available. + *

    Will only be called if {@link Player#COMMAND_ADJUST_DEVICE_VOLUME} or {@link + * Player#COMMAND_ADJUST_DEVICE_VOLUME_WITH_FLAGS} is available. + * + * @param flags Either 0 or a bitwise combination of one or more {@link C.VolumeFlags}. + * @return A {@link ListenableFuture} indicating the completion of all immediate {@link State} + * changes caused by this call. + */ + @ForOverride + protected ListenableFuture handleDecreaseDeviceVolume(@C.VolumeFlags int flags) { + throw new IllegalStateException( + "Missing implementation to handle COMMAND_ADJUST_DEVICE_VOLUME or" + + " COMMAND_ADJUST_DEVICE_VOLUME_WITH_FLAGS"); + } + + /** + * Handles calls to {@link Player#setDeviceMuted(boolean)} and {@link + * Player#setDeviceMuted(boolean, int)}. + * + *

    Will only be called if {@link Player#COMMAND_ADJUST_DEVICE_VOLUME} or {@link + * Player#COMMAND_ADJUST_DEVICE_VOLUME} is available. * * @param muted Whether the device was requested to be muted. + * @param flags Either 0 or a bitwise combination of one or more {@link C.VolumeFlags}. * @return A {@link ListenableFuture} indicating the completion of all immediate {@link State} * changes caused by this call. */ @ForOverride - protected ListenableFuture handleSetDeviceMuted(boolean muted) { + protected ListenableFuture handleSetDeviceMuted(boolean muted, @C.VolumeFlags int flags) { throw new IllegalStateException( - "Missing implementation to handle COMMAND_ADJUST_DEVICE_VOLUME"); + "Missing implementation to handle COMMAND_ADJUST_DEVICE_VOLUME or" + + " COMMAND_ADJUST_DEVICE_VOLUME_WITH_FLAGS"); } /** diff --git a/libraries/common/src/test/java/androidx/media3/common/SimpleBasePlayerTest.java b/libraries/common/src/test/java/androidx/media3/common/SimpleBasePlayerTest.java index 2c4aae495f..8727a1be68 100644 --- a/libraries/common/src/test/java/androidx/media3/common/SimpleBasePlayerTest.java +++ b/libraries/common/src/test/java/androidx/media3/common/SimpleBasePlayerTest.java @@ -3190,6 +3190,8 @@ public class SimpleBasePlayerTest { .build(); // Set a different one to the one requested to ensure the updated state is used. State updatedState = state.buildUpon().setDeviceVolume(6).build(); + AtomicInteger flagsFromHandlerRef = new AtomicInteger(); + int volumeFlags = C.VOLUME_FLAG_SHOW_UI | C.VOLUME_FLAG_VIBRATE; SimpleBasePlayer player = new SimpleBasePlayer(Looper.myLooper()) { private State playerState = state; @@ -3200,18 +3202,20 @@ public class SimpleBasePlayerTest { } @Override - protected ListenableFuture handleSetDeviceVolume(int volume) { + protected ListenableFuture handleSetDeviceVolume(int volume, int flags) { playerState = updatedState; + flagsFromHandlerRef.set(flags); return Futures.immediateVoidFuture(); } }; Listener listener = mock(Listener.class); player.addListener(listener); - player.setDeviceVolume(3); + player.setDeviceVolume(3, volumeFlags); assertThat(player.getDeviceVolume()).isEqualTo(6); verify(listener).onDeviceVolumeChanged(6, /* muted= */ false); + assertThat(flagsFromHandlerRef.get()).isEqualTo(volumeFlags); verifyNoMoreInteractions(listener); } @@ -3222,6 +3226,8 @@ public class SimpleBasePlayerTest { .setAvailableCommands(new Commands.Builder().addAllCommands().build()) .build(); // Set a new volume to see a difference between the placeholder and new state. + int volumeFlags = C.VOLUME_FLAG_SHOW_UI | C.VOLUME_FLAG_VIBRATE; + AtomicInteger flagsFromHandlerRef = new AtomicInteger(); State updatedState = state.buildUpon().setDeviceVolume(6).build(); SettableFuture future = SettableFuture.create(); SimpleBasePlayer player = @@ -3232,18 +3238,20 @@ public class SimpleBasePlayerTest { } @Override - protected ListenableFuture handleSetDeviceVolume(int volume) { + protected ListenableFuture handleSetDeviceVolume(int volume, int flags) { + flagsFromHandlerRef.set(flags); return future; } }; Listener listener = mock(Listener.class); player.addListener(listener); - player.setDeviceVolume(3); + player.setDeviceVolume(3, volumeFlags); // Verify placeholder state and listener calls. assertThat(player.getDeviceVolume()).isEqualTo(3); verify(listener).onDeviceVolumeChanged(3, /* muted= */ false); + assertThat(flagsFromHandlerRef.get()).isEqualTo(volumeFlags); verifyNoMoreInteractions(listener); future.set(null); @@ -3261,9 +3269,11 @@ public class SimpleBasePlayerTest { .setAvailableCommands( new Commands.Builder() .addAllCommands() - .remove(Player.COMMAND_SET_DEVICE_VOLUME) + .remove(Player.COMMAND_SET_DEVICE_VOLUME_WITH_FLAGS) .build()) .build(); + int volumeFlags = C.VOLUME_FLAG_SHOW_UI | C.VOLUME_FLAG_REMOVE_SOUND_AND_VIBRATE; + AtomicInteger flagsFromHandlerRef = new AtomicInteger(); AtomicBoolean callForwarded = new AtomicBoolean(); SimpleBasePlayer player = new SimpleBasePlayer(Looper.myLooper()) { @@ -3273,14 +3283,16 @@ public class SimpleBasePlayerTest { } @Override - protected ListenableFuture handleSetDeviceVolume(int volume) { + protected ListenableFuture handleSetDeviceVolume(int volume, int flags) { callForwarded.set(true); + flagsFromHandlerRef.set(flags); return Futures.immediateVoidFuture(); } }; - player.setDeviceVolume(3); + player.setDeviceVolume(3, volumeFlags); + assertThat(flagsFromHandlerRef.get()).isEqualTo(0); // no flags have been passed assertThat(callForwarded.get()).isFalse(); } @@ -3292,6 +3304,7 @@ public class SimpleBasePlayerTest { .setDeviceVolume(3) .build(); // Set a different one to the one requested to ensure the updated state is used. + int volumeFlags = C.VOLUME_FLAG_SHOW_UI | C.VOLUME_FLAG_PLAY_SOUND; State updatedState = state.buildUpon().setDeviceVolume(6).build(); SimpleBasePlayer player = new SimpleBasePlayer(Looper.myLooper()) { @@ -3303,7 +3316,7 @@ public class SimpleBasePlayerTest { } @Override - protected ListenableFuture handleIncreaseDeviceVolume() { + protected ListenableFuture handleIncreaseDeviceVolume(@C.VolumeFlags int flags) { playerState = updatedState; return Futures.immediateVoidFuture(); } @@ -3311,7 +3324,7 @@ public class SimpleBasePlayerTest { Listener listener = mock(Listener.class); player.addListener(listener); - player.increaseDeviceVolume(); + player.increaseDeviceVolume(volumeFlags); assertThat(player.getDeviceVolume()).isEqualTo(6); verify(listener).onDeviceVolumeChanged(6, /* muted= */ false); @@ -3326,6 +3339,7 @@ public class SimpleBasePlayerTest { .setDeviceVolume(3) .build(); // Set a new volume to see a difference between the placeholder and new state. + int volumeFlags = C.VOLUME_FLAG_SHOW_UI | C.VOLUME_FLAG_PLAY_SOUND; State updatedState = state.buildUpon().setDeviceVolume(6).build(); SettableFuture future = SettableFuture.create(); SimpleBasePlayer player = @@ -3336,14 +3350,14 @@ public class SimpleBasePlayerTest { } @Override - protected ListenableFuture handleIncreaseDeviceVolume() { + protected ListenableFuture handleIncreaseDeviceVolume(@C.VolumeFlags int flags) { return future; } }; Listener listener = mock(Listener.class); player.addListener(listener); - player.increaseDeviceVolume(); + player.increaseDeviceVolume(volumeFlags); // Verify placeholder state and listener calls. assertThat(player.getDeviceVolume()).isEqualTo(4); @@ -3365,9 +3379,10 @@ public class SimpleBasePlayerTest { .setAvailableCommands( new Commands.Builder() .addAllCommands() - .remove(Player.COMMAND_ADJUST_DEVICE_VOLUME) + .remove(Player.COMMAND_ADJUST_DEVICE_VOLUME_WITH_FLAGS) .build()) .build(); + int volumeFlags = C.VOLUME_FLAG_SHOW_UI | C.VOLUME_FLAG_PLAY_SOUND; AtomicBoolean callForwarded = new AtomicBoolean(); SimpleBasePlayer player = new SimpleBasePlayer(Looper.myLooper()) { @@ -3377,13 +3392,13 @@ public class SimpleBasePlayerTest { } @Override - protected ListenableFuture handleIncreaseDeviceVolume() { + protected ListenableFuture handleIncreaseDeviceVolume(@C.VolumeFlags int flags) { callForwarded.set(true); return Futures.immediateVoidFuture(); } }; - player.increaseDeviceVolume(); + player.increaseDeviceVolume(volumeFlags); assertThat(callForwarded.get()).isFalse(); } @@ -3397,6 +3412,7 @@ public class SimpleBasePlayerTest { .build(); // Set a different one to the one requested to ensure the updated state is used. State updatedState = state.buildUpon().setDeviceVolume(1).build(); + int volumeFlags = C.VOLUME_FLAG_SHOW_UI | C.VOLUME_FLAG_PLAY_SOUND; SimpleBasePlayer player = new SimpleBasePlayer(Looper.myLooper()) { private State playerState = state; @@ -3407,7 +3423,7 @@ public class SimpleBasePlayerTest { } @Override - protected ListenableFuture handleDecreaseDeviceVolume() { + protected ListenableFuture handleDecreaseDeviceVolume(@C.VolumeFlags int flags) { playerState = updatedState; return Futures.immediateVoidFuture(); } @@ -3415,7 +3431,7 @@ public class SimpleBasePlayerTest { Listener listener = mock(Listener.class); player.addListener(listener); - player.decreaseDeviceVolume(); + player.decreaseDeviceVolume(volumeFlags); assertThat(player.getDeviceVolume()).isEqualTo(1); verify(listener).onDeviceVolumeChanged(1, /* muted= */ false); @@ -3430,6 +3446,7 @@ public class SimpleBasePlayerTest { .setDeviceVolume(3) .build(); // Set a new volume to see a difference between the placeholder and new state. + int volumeFlags = C.VOLUME_FLAG_SHOW_UI | C.VOLUME_FLAG_VIBRATE; State updatedState = state.buildUpon().setDeviceVolume(1).build(); SettableFuture future = SettableFuture.create(); SimpleBasePlayer player = @@ -3440,14 +3457,14 @@ public class SimpleBasePlayerTest { } @Override - protected ListenableFuture handleDecreaseDeviceVolume() { + protected ListenableFuture handleDecreaseDeviceVolume(@C.VolumeFlags int flags) { return future; } }; Listener listener = mock(Listener.class); player.addListener(listener); - player.decreaseDeviceVolume(); + player.decreaseDeviceVolume(volumeFlags); // Verify placeholder state and listener calls. assertThat(player.getDeviceVolume()).isEqualTo(2); @@ -3469,9 +3486,10 @@ public class SimpleBasePlayerTest { .setAvailableCommands( new Commands.Builder() .addAllCommands() - .remove(Player.COMMAND_ADJUST_DEVICE_VOLUME) + .remove(Player.COMMAND_ADJUST_DEVICE_VOLUME_WITH_FLAGS) .build()) .build(); + int volumeFlags = C.VOLUME_FLAG_SHOW_UI | C.VOLUME_FLAG_VIBRATE; AtomicBoolean callForwarded = new AtomicBoolean(); SimpleBasePlayer player = new SimpleBasePlayer(Looper.myLooper()) { @@ -3481,13 +3499,13 @@ public class SimpleBasePlayerTest { } @Override - protected ListenableFuture handleDecreaseDeviceVolume() { + protected ListenableFuture handleDecreaseDeviceVolume(@C.VolumeFlags int flags) { callForwarded.set(true); return Futures.immediateVoidFuture(); } }; - player.decreaseDeviceVolume(); + player.decreaseDeviceVolume(volumeFlags); assertThat(callForwarded.get()).isFalse(); } @@ -3499,6 +3517,7 @@ public class SimpleBasePlayerTest { .setAvailableCommands(new Commands.Builder().addAllCommands().build()) .build(); // Also change the volume to ensure the updated state is used. + int volumeFlags = C.VOLUME_FLAG_VIBRATE; State updatedState = state.buildUpon().setIsDeviceMuted(true).setDeviceVolume(6).build(); SimpleBasePlayer player = new SimpleBasePlayer(Looper.myLooper()) { @@ -3510,7 +3529,8 @@ public class SimpleBasePlayerTest { } @Override - protected ListenableFuture handleSetDeviceMuted(boolean muted) { + protected ListenableFuture handleSetDeviceMuted( + boolean muted, @C.VolumeFlags int flags) { playerState = updatedState; return Futures.immediateVoidFuture(); } @@ -3518,7 +3538,7 @@ public class SimpleBasePlayerTest { Listener listener = mock(Listener.class); player.addListener(listener); - player.setDeviceMuted(true); + player.setDeviceMuted(true, volumeFlags); assertThat(player.isDeviceMuted()).isTrue(); assertThat(player.getDeviceVolume()).isEqualTo(6); @@ -3532,6 +3552,7 @@ public class SimpleBasePlayerTest { new State.Builder() .setAvailableCommands(new Commands.Builder().addAllCommands().build()) .build(); + int volumeFlags = C.VOLUME_FLAG_VIBRATE; SettableFuture future = SettableFuture.create(); SimpleBasePlayer player = new SimpleBasePlayer(Looper.myLooper()) { @@ -3543,14 +3564,15 @@ public class SimpleBasePlayerTest { } @Override - protected ListenableFuture handleSetDeviceMuted(boolean muted) { + protected ListenableFuture handleSetDeviceMuted( + boolean muted, @C.VolumeFlags int flags) { return future; } }; Listener listener = mock(Listener.class); player.addListener(listener); - player.setDeviceMuted(true); + player.setDeviceMuted(true, volumeFlags); // Verify placeholder state and listener calls. assertThat(player.isDeviceMuted()).isTrue(); @@ -3572,9 +3594,10 @@ public class SimpleBasePlayerTest { .setAvailableCommands( new Commands.Builder() .addAllCommands() - .remove(Player.COMMAND_ADJUST_DEVICE_VOLUME) + .remove(Player.COMMAND_ADJUST_DEVICE_VOLUME_WITH_FLAGS) .build()) .build(); + int volumeFlags = C.VOLUME_FLAG_VIBRATE; AtomicBoolean callForwarded = new AtomicBoolean(); SimpleBasePlayer player = new SimpleBasePlayer(Looper.myLooper()) { @@ -3584,13 +3607,14 @@ public class SimpleBasePlayerTest { } @Override - protected ListenableFuture handleSetDeviceMuted(boolean muted) { + protected ListenableFuture handleSetDeviceMuted( + boolean muted, @C.VolumeFlags int flags) { callForwarded.set(true); return Futures.immediateVoidFuture(); } }; - player.setDeviceMuted(true); + player.setDeviceMuted(true, volumeFlags); assertThat(callForwarded.get()).isFalse(); } diff --git a/libraries/exoplayer/src/androidTest/java/androidx/media3/exoplayer/StreamVolumeManagerTest.java b/libraries/exoplayer/src/androidTest/java/androidx/media3/exoplayer/StreamVolumeManagerTest.java index df1ea2f4a0..e7dd210ddb 100644 --- a/libraries/exoplayer/src/androidTest/java/androidx/media3/exoplayer/StreamVolumeManagerTest.java +++ b/libraries/exoplayer/src/androidTest/java/androidx/media3/exoplayer/StreamVolumeManagerTest.java @@ -102,11 +102,12 @@ public class StreamVolumeManagerTest { if (minVolume == maxVolume) { return; } + int volumeFlags = C.VOLUME_FLAG_SHOW_UI | C.VOLUME_FLAG_VIBRATE; int oldVolume = streamVolumeManager.getVolume(); int targetVolume = oldVolume == maxVolume ? minVolume : maxVolume; - streamVolumeManager.setVolume(targetVolume); + streamVolumeManager.setVolume(targetVolume, volumeFlags); assertThat(streamVolumeManager.getVolume()).isEqualTo(targetVolume); assertThat(testListener.lastStreamVolume).isEqualTo(targetVolume); @@ -121,11 +122,12 @@ public class StreamVolumeManagerTest { int maxVolume = streamVolumeManager.getMaxVolume(); int minVolume = streamVolumeManager.getMinVolume(); int oldVolume = streamVolumeManager.getVolume(); + int volumeFlags = C.VOLUME_FLAG_SHOW_UI | C.VOLUME_FLAG_VIBRATE; - streamVolumeManager.setVolume(maxVolume + 1); + streamVolumeManager.setVolume(maxVolume + 1, volumeFlags); assertThat(streamVolumeManager.getVolume()).isEqualTo(oldVolume); - streamVolumeManager.setVolume(minVolume - 1); + streamVolumeManager.setVolume(minVolume - 1, volumeFlags); assertThat(streamVolumeManager.getVolume()).isEqualTo(oldVolume); }); } @@ -139,11 +141,12 @@ public class StreamVolumeManagerTest { if (minVolume == maxVolume) { return; } + int volumeFlags = C.VOLUME_FLAG_SHOW_UI | C.VOLUME_FLAG_VIBRATE; - streamVolumeManager.setVolume(minVolume); + streamVolumeManager.setVolume(minVolume, volumeFlags); int targetVolume = minVolume + 1; - streamVolumeManager.increaseVolume(); + streamVolumeManager.increaseVolume(volumeFlags); assertThat(streamVolumeManager.getVolume()).isEqualTo(targetVolume); assertThat(testListener.lastStreamVolume).isEqualTo(targetVolume); @@ -156,9 +159,10 @@ public class StreamVolumeManagerTest { testThread.runOnMainThread( () -> { int maxVolume = streamVolumeManager.getMaxVolume(); + int volumeFlags = C.VOLUME_FLAG_SHOW_UI | C.VOLUME_FLAG_VIBRATE; - streamVolumeManager.setVolume(maxVolume); - streamVolumeManager.increaseVolume(); + streamVolumeManager.setVolume(maxVolume, volumeFlags); + streamVolumeManager.increaseVolume(volumeFlags); assertThat(streamVolumeManager.getVolume()).isEqualTo(maxVolume); }); @@ -173,11 +177,12 @@ public class StreamVolumeManagerTest { if (minVolume == maxVolume) { return; } + int volumeFlags = C.VOLUME_FLAG_SHOW_UI | C.VOLUME_FLAG_VIBRATE; - streamVolumeManager.setVolume(maxVolume); + streamVolumeManager.setVolume(maxVolume, volumeFlags); int targetVolume = maxVolume - 1; - streamVolumeManager.decreaseVolume(); + streamVolumeManager.decreaseVolume(volumeFlags); assertThat(streamVolumeManager.getVolume()).isEqualTo(targetVolume); assertThat(testListener.lastStreamVolume).isEqualTo(targetVolume); @@ -190,9 +195,10 @@ public class StreamVolumeManagerTest { testThread.runOnMainThread( () -> { int minVolume = streamVolumeManager.getMinVolume(); + int volumeFlags = C.VOLUME_FLAG_SHOW_UI | C.VOLUME_FLAG_VIBRATE; - streamVolumeManager.setVolume(minVolume); - streamVolumeManager.decreaseVolume(); + streamVolumeManager.setVolume(minVolume, volumeFlags); + streamVolumeManager.decreaseVolume(volumeFlags); assertThat(streamVolumeManager.getVolume()).isEqualTo(minVolume); }); @@ -207,15 +213,16 @@ public class StreamVolumeManagerTest { if (minVolume == maxVolume || minVolume > 0) { return; } + int volumeFlags = C.VOLUME_FLAG_SHOW_UI | C.VOLUME_FLAG_VIBRATE; - streamVolumeManager.setVolume(maxVolume); + streamVolumeManager.setVolume(maxVolume, volumeFlags); assertThat(streamVolumeManager.isMuted()).isFalse(); - streamVolumeManager.setMuted(true); + streamVolumeManager.setMuted(true, volumeFlags); assertThat(streamVolumeManager.isMuted()).isTrue(); assertThat(testListener.lastStreamVolumeMuted).isTrue(); - streamVolumeManager.setMuted(false); + streamVolumeManager.setMuted(false, volumeFlags); assertThat(streamVolumeManager.isMuted()).isFalse(); assertThat(testListener.lastStreamVolumeMuted).isFalse(); assertThat(testListener.lastStreamVolume).isEqualTo(maxVolume); @@ -231,6 +238,7 @@ public class StreamVolumeManagerTest { if (minVolume == maxVolume) { return; } + int volumeFlags = C.VOLUME_FLAG_SHOW_UI | C.VOLUME_FLAG_VIBRATE; int testStreamType = C.STREAM_TYPE_ALARM; int testStreamVolume = audioManager.getStreamVolume(testStreamType); @@ -238,7 +246,7 @@ public class StreamVolumeManagerTest { int oldVolume = streamVolumeManager.getVolume(); if (oldVolume == testStreamVolume) { int differentVolume = oldVolume == minVolume ? maxVolume : minVolume; - streamVolumeManager.setVolume(differentVolume); + streamVolumeManager.setVolume(differentVolume, volumeFlags); } streamVolumeManager.setStreamType(testStreamType); diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/ExoPlayerImpl.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/ExoPlayerImpl.java index a237406f75..7b98ece44d 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/ExoPlayerImpl.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/ExoPlayerImpl.java @@ -309,7 +309,9 @@ import java.util.concurrent.TimeoutException; COMMAND_GET_DEVICE_VOLUME, COMMAND_SET_VOLUME, COMMAND_SET_DEVICE_VOLUME, + COMMAND_SET_DEVICE_VOLUME_WITH_FLAGS, COMMAND_ADJUST_DEVICE_VOLUME, + COMMAND_ADJUST_DEVICE_VOLUME_WITH_FLAGS, COMMAND_SET_VIDEO_SURFACE, COMMAND_GET_TEXT, COMMAND_RELEASE) @@ -1703,28 +1705,68 @@ import java.util.concurrent.TimeoutException; return streamVolumeManager.isMuted(); } + /** + * @deprecated Use {@link #setDeviceVolume(int, int)} instead. + */ + @Deprecated @Override public void setDeviceVolume(int volume) { verifyApplicationThread(); - streamVolumeManager.setVolume(volume); + streamVolumeManager.setVolume(volume, C.VOLUME_FLAG_SHOW_UI); } + @Override + public void setDeviceVolume(int volume, @C.VolumeFlags int flags) { + verifyApplicationThread(); + streamVolumeManager.setVolume(volume, flags); + } + + /** + * @deprecated Use {@link #increaseDeviceVolume(int)} instead. + */ + @Deprecated @Override public void increaseDeviceVolume() { verifyApplicationThread(); - streamVolumeManager.increaseVolume(); + streamVolumeManager.increaseVolume(C.VOLUME_FLAG_SHOW_UI); } + @Override + public void increaseDeviceVolume(@C.VolumeFlags int flags) { + verifyApplicationThread(); + streamVolumeManager.increaseVolume(flags); + } + + /** + * @deprecated Use {@link #decreaseDeviceVolume(int)} instead. + */ + @Deprecated @Override public void decreaseDeviceVolume() { verifyApplicationThread(); - streamVolumeManager.decreaseVolume(); + streamVolumeManager.decreaseVolume(C.VOLUME_FLAG_SHOW_UI); } + @Override + public void decreaseDeviceVolume(@C.VolumeFlags int flags) { + verifyApplicationThread(); + streamVolumeManager.decreaseVolume(flags); + } + + /** + * @deprecated Use {@link #setDeviceMuted(boolean, int)} instead. + */ + @Deprecated @Override public void setDeviceMuted(boolean muted) { verifyApplicationThread(); - streamVolumeManager.setMuted(muted); + streamVolumeManager.setMuted(muted, C.VOLUME_FLAG_SHOW_UI); + } + + @Override + public void setDeviceMuted(boolean muted, @C.VolumeFlags int flags) { + verifyApplicationThread(); + streamVolumeManager.setMuted(muted, flags); } @Override diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/SimpleExoPlayer.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/SimpleExoPlayer.java index fdcbd78ba0..1ccc62c0ad 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/SimpleExoPlayer.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/SimpleExoPlayer.java @@ -1277,30 +1277,70 @@ public class SimpleExoPlayer extends BasePlayer return player.isDeviceMuted(); } + /** + * @deprecated Use {@link #setDeviceVolume(int, int)} instead. + */ + @Deprecated @Override public void setDeviceVolume(int volume) { blockUntilConstructorFinished(); player.setDeviceVolume(volume); } + @Override + public void setDeviceVolume(int volume, @C.VolumeFlags int flags) { + blockUntilConstructorFinished(); + player.setDeviceVolume(volume, flags); + } + + /** + * @deprecated Use {@link #increaseDeviceVolume(int)} instead. + */ + @Deprecated @Override public void increaseDeviceVolume() { blockUntilConstructorFinished(); player.increaseDeviceVolume(); } + @Override + public void increaseDeviceVolume(@C.VolumeFlags int flags) { + blockUntilConstructorFinished(); + player.increaseDeviceVolume(flags); + } + + /** + * @deprecated Use {@link #decreaseDeviceVolume(int)} instead. + */ + @Deprecated @Override public void decreaseDeviceVolume() { blockUntilConstructorFinished(); player.decreaseDeviceVolume(); } + @Override + public void decreaseDeviceVolume(@C.VolumeFlags int flags) { + blockUntilConstructorFinished(); + player.decreaseDeviceVolume(flags); + } + + /** + * @deprecated Use {@link #setDeviceMuted(boolean, int)} instead. + */ + @Deprecated @Override public void setDeviceMuted(boolean muted) { blockUntilConstructorFinished(); player.setDeviceMuted(muted); } + @Override + public void setDeviceMuted(boolean muted, @C.VolumeFlags int flags) { + blockUntilConstructorFinished(); + player.setDeviceMuted(muted, flags); + } + @Override public boolean isTunnelingEnabled() { blockUntilConstructorFinished(); diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/StreamVolumeManager.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/StreamVolumeManager.java index c5a8230154..03b65cc63e 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/StreamVolumeManager.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/StreamVolumeManager.java @@ -46,9 +46,6 @@ import androidx.media3.common.util.Util; // Copied from AudioManager#VOLUME_CHANGED_ACTION private static final String VOLUME_CHANGED_ACTION = "android.media.VOLUME_CHANGED_ACTION"; - // TODO(b/153317944): Allow users to override these flags. - private static final int VOLUME_FLAGS = AudioManager.FLAG_SHOW_UI; - private final Context applicationContext; private final Handler eventHandler; private final Listener listener; @@ -120,46 +117,58 @@ import androidx.media3.common.util.Util; } /** - * Sets the volume with the given value for the current audio stream. The value should be between - * {@link #getMinVolume()} and {@link #getMaxVolume()}, otherwise it will be ignored. + * Sets the volume with the given value for the current audio stream with specified volume flags. + * + * @param volume The value should be between {@link #getMinVolume()} and {@link #getMaxVolume()}, + * otherwise the volume will not be changed. + * @param flags Either 0 or a bitwise combination of one or more {@link C.VolumeFlags}. */ - public void setVolume(int volume) { + public void setVolume(int volume, @C.VolumeFlags int flags) { if (volume < getMinVolume() || volume > getMaxVolume()) { return; } - audioManager.setStreamVolume(streamType, volume, VOLUME_FLAGS); + audioManager.setStreamVolume(streamType, volume, flags); updateVolumeAndNotifyIfChanged(); } /** - * Increases the volume by one for the current audio stream. It will be ignored if the current - * volume is equal to {@link #getMaxVolume()}. + * Increases the volume by one for the current audio stream with specified volume flags. If the + * current volume is equal to {@link #getMaxVolume()}, it will not be increased. + * + * @param flags Either 0 or a bitwise combination of one or more {@link C.VolumeFlags}. */ - public void increaseVolume() { + public void increaseVolume(@C.VolumeFlags int flags) { if (volume >= getMaxVolume()) { return; } - audioManager.adjustStreamVolume(streamType, AudioManager.ADJUST_RAISE, VOLUME_FLAGS); + audioManager.adjustStreamVolume(streamType, AudioManager.ADJUST_RAISE, flags); updateVolumeAndNotifyIfChanged(); } /** - * Decreases the volume by one for the current audio stream. It will be ignored if the current - * volume is equal to {@link #getMinVolume()}. + * Decreases the volume by one for the current audio stream with specified volume flags. If the + * current volume is equal to {@link #getMinVolume()}, it will be be decreased. + * + * @param flags Either 0 or a bitwise combination of one or more {@link C.VolumeFlags}. */ - public void decreaseVolume() { + public void decreaseVolume(@C.VolumeFlags int flags) { if (volume <= getMinVolume()) { return; } - audioManager.adjustStreamVolume(streamType, AudioManager.ADJUST_LOWER, VOLUME_FLAGS); + audioManager.adjustStreamVolume(streamType, AudioManager.ADJUST_LOWER, flags); updateVolumeAndNotifyIfChanged(); } - /** Sets the mute state of the current audio stream. */ - public void setMuted(boolean muted) { + /** + * Sets the mute state of the current audio stream with specified volume flags. + * + * @param muted Whether to mute or to unmute the stream. + * @param flags Either 0 or a bitwise combination of one or more {@link C.VolumeFlags}. + */ + public void setMuted(boolean muted, @C.VolumeFlags int flags) { if (Util.SDK_INT >= 23) { audioManager.adjustStreamVolume( - streamType, muted ? AudioManager.ADJUST_MUTE : AudioManager.ADJUST_UNMUTE, VOLUME_FLAGS); + streamType, muted ? AudioManager.ADJUST_MUTE : AudioManager.ADJUST_UNMUTE, flags); } else { audioManager.setStreamMute(streamType, muted); } diff --git a/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/ExoPlayerTest.java b/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/ExoPlayerTest.java index df6cfc3d53..83f0f19ecb 100644 --- a/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/ExoPlayerTest.java +++ b/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/ExoPlayerTest.java @@ -16,6 +16,7 @@ package androidx.media3.exoplayer; import static androidx.media3.common.Player.COMMAND_ADJUST_DEVICE_VOLUME; +import static androidx.media3.common.Player.COMMAND_ADJUST_DEVICE_VOLUME_WITH_FLAGS; import static androidx.media3.common.Player.COMMAND_CHANGE_MEDIA_ITEMS; import static androidx.media3.common.Player.COMMAND_GET_AUDIO_ATTRIBUTES; import static androidx.media3.common.Player.COMMAND_GET_CURRENT_MEDIA_ITEM; @@ -38,6 +39,7 @@ 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_SET_DEVICE_VOLUME; +import static androidx.media3.common.Player.COMMAND_SET_DEVICE_VOLUME_WITH_FLAGS; import static androidx.media3.common.Player.COMMAND_SET_MEDIA_ITEM; import static androidx.media3.common.Player.COMMAND_SET_PLAYLIST_METADATA; import static androidx.media3.common.Player.COMMAND_SET_REPEAT_MODE; @@ -12250,11 +12252,13 @@ public final class ExoPlayerTest { player.addListener(listener); int deviceVolume = player.getDeviceVolume(); + int noVolumeFlags = 0; + int volumeFlags = C.VOLUME_FLAG_PLAY_SOUND | C.VOLUME_FLAG_VIBRATE; try { - player.setDeviceVolume(deviceVolume + 1); // No-op if at max volume. - player.setDeviceVolume(deviceVolume - 1); // No-op if at min volume. + player.setDeviceVolume(deviceVolume + 1, noVolumeFlags); // No-op if at max volume. + player.setDeviceVolume(deviceVolume - 1, noVolumeFlags); // No-op if at min volume. } finally { - player.setDeviceVolume(deviceVolume); // Restore original volume. + player.setDeviceVolume(deviceVolume, volumeFlags); // Restore original volume. } player.release(); @@ -12425,7 +12429,9 @@ public final class ExoPlayerTest { COMMAND_GET_DEVICE_VOLUME, COMMAND_SET_VOLUME, COMMAND_SET_DEVICE_VOLUME, + COMMAND_SET_DEVICE_VOLUME_WITH_FLAGS, COMMAND_ADJUST_DEVICE_VOLUME, + COMMAND_ADJUST_DEVICE_VOLUME_WITH_FLAGS, COMMAND_SET_VIDEO_SURFACE, COMMAND_GET_TEXT, COMMAND_SET_TRACK_SELECTION_PARAMETERS, diff --git a/libraries/session/src/main/aidl/androidx/media3/session/IMediaController.aidl b/libraries/session/src/main/aidl/androidx/media3/session/IMediaController.aidl index 7c1eb001d2..70def4bc11 100644 --- a/libraries/session/src/main/aidl/androidx/media3/session/IMediaController.aidl +++ b/libraries/session/src/main/aidl/androidx/media3/session/IMediaController.aidl @@ -23,7 +23,6 @@ import androidx.media3.session.IMediaSession; * *

    It's for internal use only, not intended to be used by library users. */ -// TODO(b/191643508): Hide the generated classes from javadoc. // Note: Keep this interface oneway. Otherwise a malicious app may make a blocking call to make // controller frozen. oneway interface IMediaController { diff --git a/libraries/session/src/main/aidl/androidx/media3/session/IMediaSession.aidl b/libraries/session/src/main/aidl/androidx/media3/session/IMediaSession.aidl index e62fa1bc7e..1d46c2e5e2 100644 --- a/libraries/session/src/main/aidl/androidx/media3/session/IMediaSession.aidl +++ b/libraries/session/src/main/aidl/androidx/media3/session/IMediaSession.aidl @@ -25,7 +25,6 @@ import androidx.media3.session.IMediaController; * *

    It's for internal use only, not intended to be used by library users. */ -// TODO(b/191643508): Hide the generated classes from javadoc. // Note: Keep this interface oneway. Otherwise a malicious app may make a blocking call to make // session frozen. oneway interface IMediaSession { @@ -34,9 +33,13 @@ oneway interface IMediaSession { void setVolume(IMediaController caller, int seq, float volume) = 3001; void setDeviceVolume(IMediaController caller, int seq, int volume) = 3002; + void setDeviceVolumeWithFlags(IMediaController caller, int seq, int volume, int flags) = 3050; void increaseDeviceVolume(IMediaController caller, int seq) = 3003; + void increaseDeviceVolumeWithFlags(IMediaController caller, int seq, int flags) = 3051; void decreaseDeviceVolume(IMediaController caller, int seq) = 3004; + void decreaseDeviceVolumeWithFlags(IMediaController caller, int seq, int flags) = 3052; void setDeviceMuted(IMediaController caller, int seq, boolean muted) = 3005; + void setDeviceMutedWithFlags(IMediaController caller, int seq, boolean muted, int flags) = 3053; void setMediaItem( IMediaController caller, int seq, @@ -115,7 +118,7 @@ oneway interface IMediaSession { void setRatingWithMediaId( IMediaController caller, int seq, String mediaId, in Bundle rating) = 3048; void setRating(IMediaController caller, int seq, in Bundle rating) = 3049; - // Next Id for MediaSession: 3050 + // Next Id for MediaSession: 3054 void getLibraryRoot(IMediaController caller, int seq, in Bundle libraryParams) = 4000; void getItem(IMediaController caller, int seq, String mediaId) = 4001; diff --git a/libraries/session/src/main/aidl/androidx/media3/session/IMediaSessionService.aidl b/libraries/session/src/main/aidl/androidx/media3/session/IMediaSessionService.aidl index 5c9b52c961..3943155a23 100644 --- a/libraries/session/src/main/aidl/androidx/media3/session/IMediaSessionService.aidl +++ b/libraries/session/src/main/aidl/androidx/media3/session/IMediaSessionService.aidl @@ -22,7 +22,6 @@ import androidx.media3.session.IMediaController; * *

    It's for internal use only, not intended to be used by library users. */ -// TODO(b/191643508): Hide the generated classes from javadoc. // Note: Keep this interface oneway. Otherwise a malicious app may make a blocking call to make // session service frozen. oneway interface IMediaSessionService { diff --git a/libraries/session/src/main/java/androidx/media3/session/MediaController.java b/libraries/session/src/main/java/androidx/media3/session/MediaController.java index dbbb9d04a2..68717bef39 100644 --- a/libraries/session/src/main/java/androidx/media3/session/MediaController.java +++ b/libraries/session/src/main/java/androidx/media3/session/MediaController.java @@ -1667,6 +1667,10 @@ public class MediaController implements Player { return impl.isDeviceMuted(); } + /** + * @deprecated Use {@link #setDeviceVolume(int, int)} instead. + */ + @Deprecated @Override public final void setDeviceVolume(@IntRange(from = 0) int volume) { verifyApplicationThread(); @@ -1677,6 +1681,19 @@ public class MediaController implements Player { impl.setDeviceVolume(volume); } + @Override + public final void setDeviceVolume(@IntRange(from = 0) int volume, @C.VolumeFlags int flags) { + verifyApplicationThread(); + if (!isConnected()) { + Log.w(TAG, "The controller is not connected. Ignoring setDeviceVolume()."); + return; + } + impl.setDeviceVolume(volume, flags); + } + /** + * @deprecated Use {@link #increaseDeviceVolume(int)} instead. + */ + @Deprecated @Override public final void increaseDeviceVolume() { verifyApplicationThread(); @@ -1687,6 +1704,19 @@ public class MediaController implements Player { impl.increaseDeviceVolume(); } + @Override + public final void increaseDeviceVolume(@C.VolumeFlags int flags) { + verifyApplicationThread(); + if (!isConnected()) { + Log.w(TAG, "The controller is not connected. Ignoring increaseDeviceVolume()."); + return; + } + impl.increaseDeviceVolume(flags); + } + /** + * @deprecated Use {@link #decreaseDeviceVolume(int)} instead. + */ + @Deprecated @Override public final void decreaseDeviceVolume() { verifyApplicationThread(); @@ -1697,6 +1727,19 @@ public class MediaController implements Player { impl.decreaseDeviceVolume(); } + @Override + public final void decreaseDeviceVolume(@C.VolumeFlags int flags) { + verifyApplicationThread(); + if (!isConnected()) { + Log.w(TAG, "The controller is not connected. Ignoring decreaseDeviceVolume()."); + return; + } + impl.decreaseDeviceVolume(flags); + } + /** + * @deprecated Use {@link #setDeviceMuted(boolean, int)} instead. + */ + @Deprecated @Override public final void setDeviceMuted(boolean muted) { verifyApplicationThread(); @@ -1707,6 +1750,16 @@ public class MediaController implements Player { impl.setDeviceMuted(muted); } + @Override + public final void setDeviceMuted(boolean muted, @C.VolumeFlags int flags) { + verifyApplicationThread(); + if (!isConnected()) { + Log.w(TAG, "The controller is not connected. Ignoring setDeviceMuted()."); + return; + } + impl.setDeviceMuted(muted, flags); + } + @Override public final MediaMetadata getMediaMetadata() { verifyApplicationThread(); @@ -2033,12 +2086,20 @@ public class MediaController implements Player { void setDeviceVolume(int volume); + void setDeviceVolume(int volume, @C.VolumeFlags int flags); + void increaseDeviceVolume(); + void increaseDeviceVolume(@C.VolumeFlags int flags); + void decreaseDeviceVolume(); + void decreaseDeviceVolume(@C.VolumeFlags int flags); + void setDeviceMuted(boolean muted); + void setDeviceMuted(boolean muted, @C.VolumeFlags int flags); + boolean getPlayWhenReady(); @PlaybackSuppressionReason diff --git a/libraries/session/src/main/java/androidx/media3/session/MediaControllerImplBase.java b/libraries/session/src/main/java/androidx/media3/session/MediaControllerImplBase.java index a5ec2e4f22..57484c0da1 100644 --- a/libraries/session/src/main/java/androidx/media3/session/MediaControllerImplBase.java +++ b/libraries/session/src/main/java/androidx/media3/session/MediaControllerImplBase.java @@ -1386,6 +1386,10 @@ import org.checkerframework.checker.nullness.qual.NonNull; return playerInfo.deviceMuted; } + /** + * @deprecated Use {@link #setDeviceVolume(int, int)} instead. + */ + @Deprecated @Override public void setDeviceVolume(int volume) { if (!isPlayerCommandAvailable(Player.COMMAND_SET_DEVICE_VOLUME)) { @@ -1405,6 +1409,29 @@ import org.checkerframework.checker.nullness.qual.NonNull; } } + @Override + public void setDeviceVolume(int volume, @C.VolumeFlags int flags) { + if (!isPlayerCommandAvailable(Player.COMMAND_SET_DEVICE_VOLUME_WITH_FLAGS)) { + return; + } + + dispatchRemoteSessionTaskWithPlayerCommand( + (iSession, seq) -> iSession.setDeviceVolumeWithFlags(controllerStub, seq, volume, flags)); + + if (playerInfo.deviceVolume != volume) { + playerInfo = playerInfo.copyWithDeviceVolume(volume, playerInfo.deviceMuted); + + listeners.queueEvent( + /* eventFlag= */ Player.EVENT_DEVICE_VOLUME_CHANGED, + listener -> listener.onDeviceVolumeChanged(volume, playerInfo.deviceMuted)); + listeners.flushEvents(); + } + } + + /** + * @deprecated Use {@link #increaseDeviceVolume(int)} instead. + */ + @Deprecated @Override public void increaseDeviceVolume() { if (!isPlayerCommandAvailable(Player.COMMAND_ADJUST_DEVICE_VOLUME)) { @@ -1424,6 +1451,29 @@ import org.checkerframework.checker.nullness.qual.NonNull; } } + @Override + public void increaseDeviceVolume(@C.VolumeFlags int flags) { + if (!isPlayerCommandAvailable(Player.COMMAND_ADJUST_DEVICE_VOLUME_WITH_FLAGS)) { + return; + } + + dispatchRemoteSessionTaskWithPlayerCommand( + (iSession, seq) -> iSession.increaseDeviceVolumeWithFlags(controllerStub, seq, flags)); + + int newDeviceVolume = playerInfo.deviceVolume + 1; + if (newDeviceVolume <= getDeviceInfo().maxVolume) { + playerInfo = playerInfo.copyWithDeviceVolume(newDeviceVolume, playerInfo.deviceMuted); + listeners.queueEvent( + /* eventFlag= */ Player.EVENT_DEVICE_VOLUME_CHANGED, + listener -> listener.onDeviceVolumeChanged(newDeviceVolume, playerInfo.deviceMuted)); + listeners.flushEvents(); + } + } + + /** + * @deprecated Use {@link #decreaseDeviceVolume(int)} instead. + */ + @Deprecated @Override public void decreaseDeviceVolume() { if (!isPlayerCommandAvailable(Player.COMMAND_ADJUST_DEVICE_VOLUME)) { @@ -1443,6 +1493,29 @@ import org.checkerframework.checker.nullness.qual.NonNull; } } + @Override + public void decreaseDeviceVolume(@C.VolumeFlags int flags) { + if (!isPlayerCommandAvailable(Player.COMMAND_ADJUST_DEVICE_VOLUME_WITH_FLAGS)) { + return; + } + + dispatchRemoteSessionTaskWithPlayerCommand( + (iSession, seq) -> iSession.decreaseDeviceVolumeWithFlags(controllerStub, seq, flags)); + + int newDeviceVolume = playerInfo.deviceVolume - 1; + if (newDeviceVolume >= getDeviceInfo().minVolume) { + playerInfo = playerInfo.copyWithDeviceVolume(newDeviceVolume, playerInfo.deviceMuted); + listeners.queueEvent( + /* eventFlag= */ Player.EVENT_DEVICE_VOLUME_CHANGED, + listener -> listener.onDeviceVolumeChanged(newDeviceVolume, playerInfo.deviceMuted)); + listeners.flushEvents(); + } + } + + /** + * @deprecated Use {@link #setDeviceMuted(boolean, int)} instead. + */ + @Deprecated @Override public void setDeviceMuted(boolean muted) { if (!isPlayerCommandAvailable(Player.COMMAND_ADJUST_DEVICE_VOLUME)) { @@ -1461,6 +1534,24 @@ import org.checkerframework.checker.nullness.qual.NonNull; } } + @Override + public void setDeviceMuted(boolean muted, @C.VolumeFlags int flags) { + if (!isPlayerCommandAvailable(Player.COMMAND_ADJUST_DEVICE_VOLUME_WITH_FLAGS)) { + return; + } + + dispatchRemoteSessionTaskWithPlayerCommand( + (iSession, seq) -> iSession.setDeviceMutedWithFlags(controllerStub, seq, muted, flags)); + + if (playerInfo.deviceMuted != muted) { + playerInfo = playerInfo.copyWithDeviceVolume(playerInfo.deviceVolume, muted); + listeners.queueEvent( + /* eventFlag= */ Player.EVENT_DEVICE_VOLUME_CHANGED, + listener -> listener.onDeviceVolumeChanged(playerInfo.deviceVolume, muted)); + listeners.flushEvents(); + } + } + @Override public VideoSize getVideoSize() { return playerInfo.videoSize; diff --git a/libraries/session/src/main/java/androidx/media3/session/MediaControllerImplLegacy.java b/libraries/session/src/main/java/androidx/media3/session/MediaControllerImplLegacy.java index 374b15216b..e67dc76b54 100644 --- a/libraries/session/src/main/java/androidx/media3/session/MediaControllerImplLegacy.java +++ b/libraries/session/src/main/java/androidx/media3/session/MediaControllerImplLegacy.java @@ -91,7 +91,6 @@ import org.checkerframework.checker.nullness.compatqual.NullableType; private static final String TAG = "MCImplLegacy"; private static final long AGGREGATES_CALLBACKS_WITHIN_TIMEOUT_MS = 500L; - private static final int VOLUME_FLAGS = AudioManager.FLAG_SHOW_UI; /* package */ final Context context; private final MediaController instance; @@ -1050,8 +1049,17 @@ import org.checkerframework.checker.nullness.compatqual.NullableType; return controllerInfo.playerInfo.deviceMuted; } + /** + * @deprecated Use {@link #setDeviceVolume(int, int)} instead. + */ + @Deprecated @Override public void setDeviceVolume(int volume) { + setDeviceVolume(volume, C.VOLUME_FLAG_SHOW_UI); + } + + @Override + public void setDeviceVolume(int volume, @C.VolumeFlags int flags) { DeviceInfo deviceInfo = getDeviceInfo(); int minVolume = deviceInfo.minVolume; int maxVolume = deviceInfo.maxVolume; @@ -1069,11 +1077,20 @@ import org.checkerframework.checker.nullness.compatqual.NullableType; /* mediaItemTransitionReason= */ null); } - controllerCompat.setVolumeTo(volume, VOLUME_FLAGS); + controllerCompat.setVolumeTo(volume, flags); + } + + /** + * @deprecated Use {@link #increaseDeviceVolume(int)} instead. + */ + @Deprecated + @Override + public void increaseDeviceVolume() { + increaseDeviceVolume(C.VOLUME_FLAG_SHOW_UI); } @Override - public void increaseDeviceVolume() { + public void increaseDeviceVolume(@C.VolumeFlags int flags) { int volume = getDeviceVolume(); int maxVolume = getDeviceInfo().maxVolume; if (volume + 1 <= maxVolume) { @@ -1090,11 +1107,20 @@ import org.checkerframework.checker.nullness.compatqual.NullableType; /* discontinuityReason= */ null, /* mediaItemTransitionReason= */ null); } - controllerCompat.adjustVolume(AudioManager.ADJUST_RAISE, VOLUME_FLAGS); + controllerCompat.adjustVolume(AudioManager.ADJUST_RAISE, flags); + } + + /** + * @deprecated Use {@link #decreaseDeviceVolume(int)} instead. + */ + @Deprecated + @Override + public void decreaseDeviceVolume() { + decreaseDeviceVolume(C.VOLUME_FLAG_SHOW_UI); } @Override - public void decreaseDeviceVolume() { + public void decreaseDeviceVolume(@C.VolumeFlags int flags) { int volume = getDeviceVolume(); int minVolume = getDeviceInfo().minVolume; @@ -1111,11 +1137,20 @@ import org.checkerframework.checker.nullness.compatqual.NullableType; /* discontinuityReason= */ null, /* mediaItemTransitionReason= */ null); } - controllerCompat.adjustVolume(AudioManager.ADJUST_LOWER, VOLUME_FLAGS); + controllerCompat.adjustVolume(AudioManager.ADJUST_LOWER, flags); + } + + /** + * @deprecated Use {@link #setDeviceMuted(boolean, int)} instead. + */ + @Deprecated + @Override + public void setDeviceMuted(boolean muted) { + setDeviceMuted(muted, C.VOLUME_FLAG_SHOW_UI); } @Override - public void setDeviceMuted(boolean muted) { + public void setDeviceMuted(boolean muted, @C.VolumeFlags int flags) { if (Util.SDK_INT < 23) { Log.w(TAG, "Session doesn't support setting mute state at API level less than 23"); return; @@ -1137,7 +1172,7 @@ import org.checkerframework.checker.nullness.compatqual.NullableType; } int direction = muted ? AudioManager.ADJUST_MUTE : AudioManager.ADJUST_UNMUTE; - controllerCompat.adjustVolume(direction, VOLUME_FLAGS); + controllerCompat.adjustVolume(direction, flags); } @Override diff --git a/libraries/session/src/main/java/androidx/media3/session/MediaSessionStub.java b/libraries/session/src/main/java/androidx/media3/session/MediaSessionStub.java index 2057dbf34d..c9ec362d0f 100644 --- a/libraries/session/src/main/java/androidx/media3/session/MediaSessionStub.java +++ b/libraries/session/src/main/java/androidx/media3/session/MediaSessionStub.java @@ -16,6 +16,7 @@ package androidx.media3.session; import static androidx.media3.common.Player.COMMAND_ADJUST_DEVICE_VOLUME; +import static androidx.media3.common.Player.COMMAND_ADJUST_DEVICE_VOLUME_WITH_FLAGS; import static androidx.media3.common.Player.COMMAND_CHANGE_MEDIA_ITEMS; import static androidx.media3.common.Player.COMMAND_PLAY_PAUSE; import static androidx.media3.common.Player.COMMAND_PREPARE; @@ -29,6 +30,7 @@ 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_SET_DEVICE_VOLUME; +import static androidx.media3.common.Player.COMMAND_SET_DEVICE_VOLUME_WITH_FLAGS; import static androidx.media3.common.Player.COMMAND_SET_MEDIA_ITEM; import static androidx.media3.common.Player.COMMAND_SET_PLAYLIST_METADATA; import static androidx.media3.common.Player.COMMAND_SET_REPEAT_MODE; @@ -1332,6 +1334,7 @@ import java.util.concurrent.ExecutionException; sendSessionResultSuccess(player -> player.setVolume(volume))); } + @SuppressWarnings("deprecation") // Backwards compatibility a for flag-less method @Override public void setDeviceVolume(@Nullable IMediaController caller, int sequenceNumber, int volume) { if (caller == null) { @@ -1344,6 +1347,20 @@ import java.util.concurrent.ExecutionException; sendSessionResultSuccess(player -> player.setDeviceVolume(volume))); } + @Override + public void setDeviceVolumeWithFlags( + @Nullable IMediaController caller, int sequenceNumber, int volume, int flags) { + if (caller == null) { + return; + } + queueSessionTaskWithPlayerCommand( + caller, + sequenceNumber, + COMMAND_SET_DEVICE_VOLUME_WITH_FLAGS, + sendSessionResultSuccess(player -> player.setDeviceVolume(volume, flags))); + } + + @SuppressWarnings("deprecation") // Backwards compatibility a for flag-less method @Override public void increaseDeviceVolume(@Nullable IMediaController caller, int sequenceNumber) { if (caller == null) { @@ -1353,9 +1370,23 @@ import java.util.concurrent.ExecutionException; caller, sequenceNumber, COMMAND_ADJUST_DEVICE_VOLUME, - sendSessionResultSuccess(Player::increaseDeviceVolume)); + sendSessionResultSuccess(player -> player.increaseDeviceVolume())); } + @Override + public void increaseDeviceVolumeWithFlags( + @Nullable IMediaController caller, int sequenceNumber, int flags) { + if (caller == null) { + return; + } + queueSessionTaskWithPlayerCommand( + caller, + sequenceNumber, + COMMAND_ADJUST_DEVICE_VOLUME_WITH_FLAGS, + sendSessionResultSuccess(player -> player.increaseDeviceVolume(flags))); + } + + @SuppressWarnings("deprecation") // Backwards compatibility a for flag-less method @Override public void decreaseDeviceVolume(@Nullable IMediaController caller, int sequenceNumber) { if (caller == null) { @@ -1365,9 +1396,23 @@ import java.util.concurrent.ExecutionException; caller, sequenceNumber, COMMAND_ADJUST_DEVICE_VOLUME, - sendSessionResultSuccess(Player::decreaseDeviceVolume)); + sendSessionResultSuccess(player -> player.decreaseDeviceVolume())); } + @Override + public void decreaseDeviceVolumeWithFlags( + @Nullable IMediaController caller, int sequenceNumber, int flags) { + if (caller == null) { + return; + } + queueSessionTaskWithPlayerCommand( + caller, + sequenceNumber, + COMMAND_ADJUST_DEVICE_VOLUME_WITH_FLAGS, + sendSessionResultSuccess(player -> player.decreaseDeviceVolume(flags))); + } + + @SuppressWarnings("deprecation") // Backwards compatibility a for flag-less method @Override public void setDeviceMuted(@Nullable IMediaController caller, int sequenceNumber, boolean muted) { if (caller == null) { @@ -1380,6 +1425,19 @@ import java.util.concurrent.ExecutionException; sendSessionResultSuccess(player -> player.setDeviceMuted(muted))); } + @Override + public void setDeviceMutedWithFlags( + @Nullable IMediaController caller, int sequenceNumber, boolean muted, int flags) { + if (caller == null) { + return; + } + queueSessionTaskWithPlayerCommand( + caller, + sequenceNumber, + COMMAND_ADJUST_DEVICE_VOLUME_WITH_FLAGS, + sendSessionResultSuccess(player -> player.setDeviceMuted(muted, flags))); + } + @Override public void setPlayWhenReady( @Nullable IMediaController caller, int sequenceNumber, boolean playWhenReady) { diff --git a/libraries/session/src/main/java/androidx/media3/session/MediaUtils.java b/libraries/session/src/main/java/androidx/media3/session/MediaUtils.java index e5860268f2..d2631c8ddb 100644 --- a/libraries/session/src/main/java/androidx/media3/session/MediaUtils.java +++ b/libraries/session/src/main/java/androidx/media3/session/MediaUtils.java @@ -18,6 +18,7 @@ package androidx.media3.session; import static android.support.v4.media.session.MediaSessionCompat.FLAG_HANDLES_QUEUE_COMMANDS; import static androidx.media.utils.MediaConstants.BROWSER_ROOT_HINTS_KEY_ROOT_CHILDREN_SUPPORTED_FLAGS; import static androidx.media3.common.Player.COMMAND_ADJUST_DEVICE_VOLUME; +import static androidx.media3.common.Player.COMMAND_ADJUST_DEVICE_VOLUME_WITH_FLAGS; import static androidx.media3.common.Player.COMMAND_CHANGE_MEDIA_ITEMS; import static androidx.media3.common.Player.COMMAND_GET_AUDIO_ATTRIBUTES; import static androidx.media3.common.Player.COMMAND_GET_CURRENT_MEDIA_ITEM; @@ -36,6 +37,7 @@ 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_SET_DEVICE_VOLUME; +import static androidx.media3.common.Player.COMMAND_SET_DEVICE_VOLUME_WITH_FLAGS; import static androidx.media3.common.Player.COMMAND_SET_MEDIA_ITEM; import static androidx.media3.common.Player.COMMAND_SET_REPEAT_MODE; import static androidx.media3.common.Player.COMMAND_SET_SHUFFLE_MODE; @@ -1094,6 +1096,7 @@ import org.checkerframework.checker.nullness.compatqual.NullableType; * @param isSessionReady Whether the session compat is ready. * @return The converted player commands. */ + @SuppressWarnings("deprecation") // Backwards compatibility with old volume commands public static Player.Commands convertToPlayerCommands( @Nullable PlaybackStateCompat playbackStateCompat, int volumeControlType, @@ -1141,9 +1144,14 @@ import org.checkerframework.checker.nullness.compatqual.NullableType; playerCommandsBuilder.add(COMMAND_STOP); } if (volumeControlType == VolumeProviderCompat.VOLUME_CONTROL_RELATIVE) { - playerCommandsBuilder.add(COMMAND_ADJUST_DEVICE_VOLUME); + playerCommandsBuilder.addAll( + COMMAND_ADJUST_DEVICE_VOLUME, COMMAND_ADJUST_DEVICE_VOLUME_WITH_FLAGS); } else if (volumeControlType == VolumeProviderCompat.VOLUME_CONTROL_ABSOLUTE) { - playerCommandsBuilder.addAll(COMMAND_ADJUST_DEVICE_VOLUME, COMMAND_SET_DEVICE_VOLUME); + playerCommandsBuilder.addAll( + COMMAND_ADJUST_DEVICE_VOLUME, + COMMAND_ADJUST_DEVICE_VOLUME_WITH_FLAGS, + COMMAND_SET_DEVICE_VOLUME, + COMMAND_SET_DEVICE_VOLUME_WITH_FLAGS); } playerCommandsBuilder.addAll( COMMAND_GET_DEVICE_VOLUME, diff --git a/libraries/session/src/main/java/androidx/media3/session/PlayerWrapper.java b/libraries/session/src/main/java/androidx/media3/session/PlayerWrapper.java index fbb466ed6e..8086c31d83 100644 --- a/libraries/session/src/main/java/androidx/media3/session/PlayerWrapper.java +++ b/libraries/session/src/main/java/androidx/media3/session/PlayerWrapper.java @@ -736,36 +736,74 @@ import java.util.List; return isCommandAvailable(Player.COMMAND_GET_DEVICE_VOLUME) && isDeviceMuted(); } + /** + * @deprecated Use {@link #setDeviceVolume(int, int)} instead. + */ + @SuppressWarnings("deprecation") // Forwarding to deprecated method + @Deprecated @Override public void setDeviceVolume(int volume) { verifyApplicationThread(); super.setDeviceVolume(volume); } - public void setDeviceVolumeIfCommandAvailable(int volume) { - if (isCommandAvailable(COMMAND_SET_DEVICE_VOLUME)) { - setDeviceVolume(volume); - } + @Override + public void setDeviceVolume(int volume, @C.VolumeFlags int flags) { + verifyApplicationThread(); + super.setDeviceVolume(volume, flags); } + /** + * @deprecated Use {@link #increaseDeviceVolume(int)} instead. + */ + @SuppressWarnings("deprecation") // Forwarding to deprecated method + @Deprecated @Override public void increaseDeviceVolume() { verifyApplicationThread(); super.increaseDeviceVolume(); } + @Override + public void increaseDeviceVolume(@C.VolumeFlags int flags) { + verifyApplicationThread(); + super.increaseDeviceVolume(flags); + } + + /** + * @deprecated Use {@link #decreaseDeviceVolume(int)} instead. + */ + @SuppressWarnings("deprecation") // Forwarding to deprecated method + @Deprecated @Override public void decreaseDeviceVolume() { verifyApplicationThread(); super.decreaseDeviceVolume(); } + @Override + public void decreaseDeviceVolume(@C.VolumeFlags int flags) { + verifyApplicationThread(); + super.decreaseDeviceVolume(flags); + } + + /** + * @deprecated Use {@link #setDeviceMuted(boolean, int)} instead. + */ + @SuppressWarnings("deprecation") // Forwarding to deprecated method + @Deprecated @Override public void setDeviceMuted(boolean muted) { verifyApplicationThread(); super.setDeviceMuted(muted); } + @Override + public void setDeviceMuted(boolean muted, @C.VolumeFlags int flags) { + verifyApplicationThread(); + super.setDeviceMuted(muted, flags); + } + @Override public void setPlayWhenReady(boolean playWhenReady) { verifyApplicationThread(); @@ -974,6 +1012,7 @@ import java.util.List; } @Nullable + @SuppressWarnings("deprecation") // Backwards compatibility with old volume commands public VolumeProviderCompat createVolumeProviderCompat() { if (getDeviceInfo().playbackType == DeviceInfo.PLAYBACK_TYPE_LOCAL) { return null; @@ -988,10 +1027,23 @@ import java.util.List; } Handler handler = new Handler(getApplicationLooper()); int currentVolume = getDeviceVolumeWithCommandCheck(); + int legacyVolumeFlag = C.VOLUME_FLAG_SHOW_UI; return new VolumeProviderCompat(volumeControlType, getDeviceInfo().maxVolume, currentVolume) { @Override public void onSetVolumeTo(int volume) { - postOrRun(handler, () -> setDeviceVolumeIfCommandAvailable(volume)); + postOrRun( + handler, + () -> { + if (!isCommandAvailable(COMMAND_SET_DEVICE_VOLUME) + && !isCommandAvailable(COMMAND_SET_DEVICE_VOLUME_WITH_FLAGS)) { + return; + } + if (isCommandAvailable(COMMAND_SET_DEVICE_VOLUME_WITH_FLAGS)) { + setDeviceVolume(volume, legacyVolumeFlag); + } else { + setDeviceVolume(volume); + } + }); } @Override @@ -999,24 +1051,45 @@ import java.util.List; postOrRun( handler, () -> { - if (!isCommandAvailable(COMMAND_ADJUST_DEVICE_VOLUME)) { + if (!isCommandAvailable(COMMAND_ADJUST_DEVICE_VOLUME) + && !isCommandAvailable(COMMAND_ADJUST_DEVICE_VOLUME_WITH_FLAGS)) { return; } switch (direction) { case AudioManager.ADJUST_RAISE: - increaseDeviceVolume(); + if (isCommandAvailable(COMMAND_ADJUST_DEVICE_VOLUME_WITH_FLAGS)) { + increaseDeviceVolume(legacyVolumeFlag); + } else { + increaseDeviceVolume(); + } break; case AudioManager.ADJUST_LOWER: - decreaseDeviceVolume(); + if (isCommandAvailable(COMMAND_ADJUST_DEVICE_VOLUME_WITH_FLAGS)) { + decreaseDeviceVolume(legacyVolumeFlag); + } else { + decreaseDeviceVolume(); + } break; case AudioManager.ADJUST_MUTE: - setDeviceMuted(true); + if (isCommandAvailable(COMMAND_ADJUST_DEVICE_VOLUME_WITH_FLAGS)) { + setDeviceMuted(true, legacyVolumeFlag); + } else { + setDeviceMuted(true); + } break; case AudioManager.ADJUST_UNMUTE: - setDeviceMuted(false); + if (isCommandAvailable(COMMAND_ADJUST_DEVICE_VOLUME_WITH_FLAGS)) { + setDeviceMuted(false, legacyVolumeFlag); + } else { + setDeviceMuted(false); + } break; case AudioManager.ADJUST_TOGGLE_MUTE: - setDeviceMuted(!isDeviceMutedWithCommandCheck()); + if (isCommandAvailable(COMMAND_ADJUST_DEVICE_VOLUME_WITH_FLAGS)) { + setDeviceMuted(!isDeviceMutedWithCommandCheck(), legacyVolumeFlag); + } else { + setDeviceMuted(!isDeviceMutedWithCommandCheck()); + } break; default: Log.w( diff --git a/libraries/test_session_common/src/main/aidl/androidx/media3/test/session/common/IRemoteMediaController.aidl b/libraries/test_session_common/src/main/aidl/androidx/media3/test/session/common/IRemoteMediaController.aidl index 5380bc1215..fa4634852f 100644 --- a/libraries/test_session_common/src/main/aidl/androidx/media3/test/session/common/IRemoteMediaController.aidl +++ b/libraries/test_session_common/src/main/aidl/androidx/media3/test/session/common/IRemoteMediaController.aidl @@ -72,9 +72,13 @@ interface IRemoteMediaController { void adjustVolume(String controllerId, int direction, int flags); void setVolume(String controllerId, float volume); void setDeviceVolume(String controllerId, int volume); + void setDeviceVolumeWithFlags(String controllerId, int volume, int flags); void increaseDeviceVolume(String controllerId); + void increaseDeviceVolumeWithFlags(String controllerId, int flags); void decreaseDeviceVolume(String controllerId); + void decreaseDeviceVolumeWithFlags(String controllerId, int flags); void setDeviceMuted(String controllerId, boolean muted); + void setDeviceMutedWithFlags(String controllerId, boolean muted, int flags); Bundle sendCustomCommand(String controllerId, in Bundle command, in Bundle args); Bundle setRatingWithMediaId(String controllerId, String mediaId, in Bundle rating); Bundle setRating(String controllerId, in Bundle rating); diff --git a/libraries/test_session_common/src/main/aidl/androidx/media3/test/session/common/IRemoteMediaSession.aidl b/libraries/test_session_common/src/main/aidl/androidx/media3/test/session/common/IRemoteMediaSession.aidl index c7b50fa114..e19132497d 100644 --- a/libraries/test_session_common/src/main/aidl/androidx/media3/test/session/common/IRemoteMediaSession.aidl +++ b/libraries/test_session_common/src/main/aidl/androidx/media3/test/session/common/IRemoteMediaSession.aidl @@ -52,6 +52,10 @@ interface IRemoteMediaSession { void setCurrentAdGroupIndex(String sessionId, int currentAdGroupIndex); void setCurrentAdIndexInAdGroup(String sessionId, int currentAdIndexInAdGroup); void setVolume(String sessionId, float volume); + void setDeviceVolume(String sessionId, int volume, int flags); + void decreaseDeviceVolume(String sessionId, int flags); + void increaseDeviceVolume(String sessionId, int flags); + void setDeviceMuted(String sessionId, boolean muted, int flags); void notifyPlayerError(String sessionId, in Bundle playerErrorBundle); void notifyPlayWhenReadyChanged(String sessionId, boolean playWhenReady, int reason); void notifyPlaybackStateChanged(String sessionId, int state); @@ -79,9 +83,8 @@ interface IRemoteMediaSession { void notifyRepeatModeChanged(String sessionId); void notifySeekBackIncrementChanged(String sessionId, long seekBackIncrementMs); void notifySeekForwardIncrementChanged(String sessionId, long seekForwardIncrementMs); - void notifyDeviceVolumeChanged(String sessionId, int volume, boolean muted); - void decreaseDeviceVolume(String sessionId); - void increaseDeviceVolume(String sessionId); + void notifyDeviceVolumeChanged(String sessionId); + void notifyVolumeChanged(String sessionId); void notifyCuesChanged(String sessionId, in Bundle cueGroup); void notifyDeviceInfoChanged(String sessionId, in Bundle deviceInfo); void notifyMediaMetadataChanged(String sessionId, in Bundle mediaMetadata); diff --git a/libraries/test_session_current/src/androidTest/java/androidx/media3/session/MediaControllerCompatCallbackWithMediaSessionTest.java b/libraries/test_session_current/src/androidTest/java/androidx/media3/session/MediaControllerCompatCallbackWithMediaSessionTest.java index bd85cf9338..70bfb171d1 100644 --- a/libraries/test_session_current/src/androidTest/java/androidx/media3/session/MediaControllerCompatCallbackWithMediaSessionTest.java +++ b/libraries/test_session_current/src/androidTest/java/androidx/media3/session/MediaControllerCompatCallbackWithMediaSessionTest.java @@ -1286,7 +1286,8 @@ public class MediaControllerCompatCallbackWithMediaSessionTest { }; controllerCompat.registerCallback(callback, handler); - session.getMockPlayer().notifyDeviceVolumeChanged(targetVolume, /* muted= */ false); + session.getMockPlayer().setDeviceVolume(targetVolume, /* flags= */ 0); + session.getMockPlayer().notifyDeviceVolumeChanged(); assertThat(targetVolumeNotified.await(TIMEOUT_MS, MILLISECONDS)).isTrue(); assertThat(controllerCompat.getPlaybackInfo().getCurrentVolume()).isEqualTo(targetVolume); diff --git a/libraries/test_session_current/src/androidTest/java/androidx/media3/session/MediaControllerListenerTest.java b/libraries/test_session_current/src/androidTest/java/androidx/media3/session/MediaControllerListenerTest.java index add2c263cc..b8d27ac58e 100644 --- a/libraries/test_session_current/src/androidTest/java/androidx/media3/session/MediaControllerListenerTest.java +++ b/libraries/test_session_current/src/androidTest/java/androidx/media3/session/MediaControllerListenerTest.java @@ -2850,7 +2850,8 @@ public class MediaControllerListenerTest { threadTestRule.getHandler().postAndSync(() -> controller.addListener(listener)); int targetVolume = 45; - remoteSession.getMockPlayer().notifyDeviceVolumeChanged(targetVolume, /* muted= */ false); + remoteSession.getMockPlayer().setDeviceVolume(targetVolume, /* flags= */ 0); + remoteSession.getMockPlayer().notifyDeviceVolumeChanged(); assertThat(latch.await(TIMEOUT_MS, MILLISECONDS)).isTrue(); assertThat(deviceVolumeFromParamRef.get()).isEqualTo(targetVolume); @@ -2889,7 +2890,8 @@ public class MediaControllerListenerTest { }; threadTestRule.getHandler().postAndSync(() -> controller.addListener(listener)); - remoteSession.getMockPlayer().notifyDeviceVolumeChanged(/* volume= */ 0, /* muted= */ true); + remoteSession.getMockPlayer().setDeviceMuted(/* muted= */ true, /* flags= */ 0); + remoteSession.getMockPlayer().notifyDeviceVolumeChanged(); assertThat(latch.await(TIMEOUT_MS, MILLISECONDS)).isTrue(); assertThat(deviceMutedFromParamRef.get()).isTrue(); @@ -2904,6 +2906,7 @@ public class MediaControllerListenerTest { new RemoteMediaSession.MockPlayerConfigBuilder().setDeviceVolume(10).build(); remoteSession.setPlayer(playerConfig); MediaController controller = controllerTestRule.createController(remoteSession.getToken()); + int volumeFlags = C.VOLUME_FLAG_VIBRATE; AtomicInteger deviceVolumeFromParamRef = new AtomicInteger(); AtomicInteger deviceVolumeFromGetterRef = new AtomicInteger(); AtomicInteger deviceVolumeFromOnEventsRef = new AtomicInteger(); @@ -2927,7 +2930,8 @@ public class MediaControllerListenerTest { }; threadTestRule.getHandler().postAndSync(() -> controller.addListener(listener)); - remoteSession.getMockPlayer().decreaseDeviceVolume(); + remoteSession.getMockPlayer().decreaseDeviceVolume(volumeFlags); + remoteSession.getMockPlayer().notifyDeviceVolumeChanged(); assertThat(latch.await(TIMEOUT_MS, MILLISECONDS)).isTrue(); assertThat(deviceVolumeFromParamRef.get()).isEqualTo(9); @@ -2943,6 +2947,7 @@ public class MediaControllerListenerTest { new RemoteMediaSession.MockPlayerConfigBuilder().setDeviceVolume(10).build(); remoteSession.setPlayer(playerConfig); MediaController controller = controllerTestRule.createController(remoteSession.getToken()); + int volumeFlags = C.VOLUME_FLAG_VIBRATE; AtomicInteger deviceVolumeFromParamRef = new AtomicInteger(); AtomicInteger deviceVolumeFromGetterRef = new AtomicInteger(); AtomicInteger deviceVolumeFromOnEventsRef = new AtomicInteger(); @@ -2966,7 +2971,8 @@ public class MediaControllerListenerTest { }; threadTestRule.getHandler().postAndSync(() -> controller.addListener(listener)); - remoteSession.getMockPlayer().increaseDeviceVolume(); + remoteSession.getMockPlayer().increaseDeviceVolume(volumeFlags); + remoteSession.getMockPlayer().notifyDeviceVolumeChanged(); assertThat(latch.await(TIMEOUT_MS, MILLISECONDS)).isTrue(); assertThat(deviceVolumeFromParamRef.get()).isEqualTo(11); @@ -3005,6 +3011,7 @@ public class MediaControllerListenerTest { threadTestRule.getHandler().postAndSync(() -> controller.addListener(listener)); remoteSession.getMockPlayer().setVolume(0.5f); + remoteSession.getMockPlayer().notifyVolumeChanged(); assertThat(latch.await(TIMEOUT_MS, MILLISECONDS)).isTrue(); assertThat(volumeFromParamRef.get()).isEqualTo(0.5f); diff --git a/libraries/test_session_current/src/androidTest/java/androidx/media3/session/MediaControllerStateMaskingTest.java b/libraries/test_session_current/src/androidTest/java/androidx/media3/session/MediaControllerStateMaskingTest.java index e923f21d5a..f2c6648071 100644 --- a/libraries/test_session_current/src/androidTest/java/androidx/media3/session/MediaControllerStateMaskingTest.java +++ b/libraries/test_session_current/src/androidTest/java/androidx/media3/session/MediaControllerStateMaskingTest.java @@ -437,6 +437,7 @@ public class MediaControllerStateMaskingTest { @Test public void setDeviceVolume() throws Exception { int testDeviceVolume = 2; + int volumeFlags = 0; Bundle playerConfig = new RemoteMediaSession.MockPlayerConfigBuilder().setDeviceVolume(0).build(); remoteSession.setPlayer(playerConfig); @@ -466,7 +467,7 @@ public class MediaControllerStateMaskingTest { .getHandler() .postAndSync( () -> { - controller.setDeviceVolume(testDeviceVolume); + controller.setDeviceVolume(testDeviceVolume, volumeFlags); deviceVolumeFromGetterRef.set(controller.getDeviceVolume()); }); @@ -480,6 +481,7 @@ public class MediaControllerStateMaskingTest { @Test public void increaseDeviceVolume() throws Exception { int testDeviceVolume = 2; + int volumeFlags = 0; Bundle playerConfig = new RemoteMediaSession.MockPlayerConfigBuilder() .setDeviceVolume(1) @@ -514,7 +516,7 @@ public class MediaControllerStateMaskingTest { .getHandler() .postAndSync( () -> { - controller.increaseDeviceVolume(); + controller.increaseDeviceVolume(volumeFlags); deviceVolumeFromGetterRef.set(controller.getDeviceVolume()); }); @@ -552,12 +554,13 @@ public class MediaControllerStateMaskingTest { }; threadTestRule.getHandler().postAndSync(() -> controller.addListener(listener)); + int volumeFlags = 0; AtomicInteger deviceVolumeFromGetterRef = new AtomicInteger(); threadTestRule .getHandler() .postAndSync( () -> { - controller.decreaseDeviceVolume(); + controller.decreaseDeviceVolume(volumeFlags); deviceVolumeFromGetterRef.set(controller.getDeviceVolume()); }); @@ -571,6 +574,7 @@ public class MediaControllerStateMaskingTest { @Test public void setDeviceMuted() throws Exception { boolean testDeviceMuted = true; + int volumeFlags = C.VOLUME_FLAG_VIBRATE; Bundle playerConfig = new RemoteMediaSession.MockPlayerConfigBuilder().setDeviceMuted(false).build(); remoteSession.setPlayer(playerConfig); @@ -600,7 +604,7 @@ public class MediaControllerStateMaskingTest { .getHandler() .postAndSync( () -> { - controller.setDeviceMuted(testDeviceMuted); + controller.setDeviceMuted(testDeviceMuted, volumeFlags); deviceMutedFromGetterRef.set(controller.isDeviceMuted()); }); diff --git a/libraries/test_session_current/src/androidTest/java/androidx/media3/session/MediaSessionCallbackWithMediaControllerCompatTest.java b/libraries/test_session_current/src/androidTest/java/androidx/media3/session/MediaSessionCallbackWithMediaControllerCompatTest.java index fcdbe1ec5a..c6220bfd27 100644 --- a/libraries/test_session_current/src/androidTest/java/androidx/media3/session/MediaSessionCallbackWithMediaControllerCompatTest.java +++ b/libraries/test_session_current/src/androidTest/java/androidx/media3/session/MediaSessionCallbackWithMediaControllerCompatTest.java @@ -43,6 +43,7 @@ import android.support.v4.media.session.PlaybackStateCompat; import androidx.media.AudioAttributesCompat; import androidx.media.AudioManagerCompat; import androidx.media3.common.AudioAttributes; +import androidx.media3.common.C; import androidx.media3.common.DeviceInfo; import androidx.media3.common.MediaItem; import androidx.media3.common.Player; @@ -664,6 +665,11 @@ public class MediaSessionCallbackWithMediaControllerCompatTest { context, session.getSessionCompat().getSessionToken(), /* waitForConnection= */ true); MockPlayer remotePlayer = new MockPlayer.Builder().setApplicationLooper(handler.getLooper()).build(); + remotePlayer.commands = + new Player.Commands.Builder() + .addAllCommands() + .remove(Player.COMMAND_SET_DEVICE_VOLUME_WITH_FLAGS) + .build(); handler.postAndSync( () -> { remotePlayer.deviceInfo = @@ -680,6 +686,35 @@ public class MediaSessionCallbackWithMediaControllerCompatTest { assertThat(remotePlayer.deviceVolume).isEqualTo(targetVolume); } + @Test + public void setVolumeTo_setsDeviceVolumeWithFlags() throws Exception { + session = + new MediaSession.Builder(context, player) + .setId("setVolumeTo_setsDeviceVolumeWithFlags") + .setCallback(new TestSessionCallback()) + .build(); + controller = + new RemoteMediaControllerCompat( + context, session.getSessionCompat().getSessionToken(), /* waitForConnection= */ true); + MockPlayer remotePlayer = + new MockPlayer.Builder().setApplicationLooper(handler.getLooper()).build(); + remotePlayer.commands = new Player.Commands.Builder().addAllCommands().build(); + handler.postAndSync( + () -> { + remotePlayer.deviceInfo = + new DeviceInfo( + DeviceInfo.PLAYBACK_TYPE_REMOTE, /* minVolume= */ 0, /* maxVolume= */ 100); + remotePlayer.deviceVolume = 23; + session.setPlayer(remotePlayer); + }); + + int targetVolume = 50; + controller.setVolumeTo(targetVolume, /* flags= */ 0); + + remotePlayer.awaitMethodCalled(MockPlayer.METHOD_SET_DEVICE_VOLUME_WITH_FLAGS, TIMEOUT_MS); + assertThat(remotePlayer.deviceVolume).isEqualTo(targetVolume); + } + @Test public void adjustVolume_raise_increasesDeviceVolume() throws Exception { session = @@ -692,6 +727,37 @@ public class MediaSessionCallbackWithMediaControllerCompatTest { context, session.getSessionCompat().getSessionToken(), /* waitForConnection= */ true); MockPlayer remotePlayer = new MockPlayer.Builder().setApplicationLooper(handler.getLooper()).build(); + remotePlayer.commands = + new Player.Commands.Builder() + .addAllCommands() + .remove(Player.COMMAND_ADJUST_DEVICE_VOLUME_WITH_FLAGS) + .build(); + handler.postAndSync( + () -> { + remotePlayer.deviceInfo = + new DeviceInfo( + DeviceInfo.PLAYBACK_TYPE_REMOTE, /* minVolume= */ 0, /* maxVolume= */ 100); + remotePlayer.deviceVolume = 23; + session.setPlayer(remotePlayer); + }); + + controller.adjustVolume(AudioManager.ADJUST_RAISE, /* flags= */ 0); + + remotePlayer.awaitMethodCalled(MockPlayer.METHOD_INCREASE_DEVICE_VOLUME, TIMEOUT_MS); + } + + @Test + public void adjustVolume_raise_increasesDeviceVolumeWithFlags() throws Exception { + session = + new MediaSession.Builder(context, player) + .setId("adjustVolume_raise_increasesDeviceVolumeWithFlags") + .setCallback(new TestSessionCallback()) + .build(); + controller = + new RemoteMediaControllerCompat( + context, session.getSessionCompat().getSessionToken(), /* waitForConnection= */ true); + MockPlayer remotePlayer = + new MockPlayer.Builder().setApplicationLooper(handler.getLooper()).build(); handler.postAndSync( () -> { remotePlayer.deviceInfo = @@ -703,7 +769,7 @@ public class MediaSessionCallbackWithMediaControllerCompatTest { controller.adjustVolume(AudioManager.ADJUST_RAISE, /* flags= */ 0); - remotePlayer.awaitMethodCalled(MockPlayer.METHOD_INCREASE_DEVICE_VOLUME, TIMEOUT_MS); + remotePlayer.awaitMethodCalled(MockPlayer.METHOD_INCREASE_DEVICE_VOLUME_WITH_FLAGS, TIMEOUT_MS); } @Test @@ -718,6 +784,11 @@ public class MediaSessionCallbackWithMediaControllerCompatTest { context, session.getSessionCompat().getSessionToken(), /* waitForConnection= */ true); MockPlayer remotePlayer = new MockPlayer.Builder().setApplicationLooper(handler.getLooper()).build(); + remotePlayer.commands = + new Player.Commands.Builder() + .addAllCommands() + .remove(Player.COMMAND_ADJUST_DEVICE_VOLUME_WITH_FLAGS) + .build(); handler.postAndSync( () -> { remotePlayer.deviceInfo = @@ -732,6 +803,33 @@ public class MediaSessionCallbackWithMediaControllerCompatTest { remotePlayer.awaitMethodCalled(MockPlayer.METHOD_DECREASE_DEVICE_VOLUME, TIMEOUT_MS); } + @Test + public void adjustVolume_lower_decreasesDeviceVolumeWithFlags() throws Exception { + session = + new MediaSession.Builder(context, player) + .setId("adjustVolume_lower_decreasesDeviceVolumeWithFlags") + .setCallback(new TestSessionCallback()) + .build(); + controller = + new RemoteMediaControllerCompat( + context, session.getSessionCompat().getSessionToken(), /* waitForConnection= */ true); + MockPlayer remotePlayer = + new MockPlayer.Builder().setApplicationLooper(handler.getLooper()).build(); + remotePlayer.commands = new Player.Commands.Builder().addAllCommands().build(); + handler.postAndSync( + () -> { + remotePlayer.deviceInfo = + new DeviceInfo( + DeviceInfo.PLAYBACK_TYPE_REMOTE, /* minVolume= */ 0, /* maxVolume= */ 100); + remotePlayer.deviceVolume = 23; + session.setPlayer(remotePlayer); + }); + + controller.adjustVolume(AudioManager.ADJUST_LOWER, /* flags= */ 0); + + remotePlayer.awaitMethodCalled(MockPlayer.METHOD_DECREASE_DEVICE_VOLUME_WITH_FLAGS, TIMEOUT_MS); + } + @Test public void setVolumeWithLocalVolume() throws Exception { if (Util.SDK_INT >= 21 && audioManager.isVolumeFixed()) { @@ -772,7 +870,7 @@ public class MediaSessionCallbackWithMediaControllerCompatTest { int targetVolume = originalVolume == minVolume ? originalVolume + 1 : originalVolume - 1; Log.d(TAG, "originalVolume=" + originalVolume + ", targetVolume=" + targetVolume); - controller.setVolumeTo(targetVolume, AudioManager.FLAG_SHOW_UI); + controller.setVolumeTo(targetVolume, C.VOLUME_FLAG_SHOW_UI); PollingCheck.waitFor( VOLUME_CHANGE_TIMEOUT_MS, () -> targetVolume == audioManager.getStreamVolume(stream)); @@ -822,7 +920,7 @@ public class MediaSessionCallbackWithMediaControllerCompatTest { int targetVolume = originalVolume + direction; Log.d(TAG, "originalVolume=" + originalVolume + ", targetVolume=" + targetVolume); - controller.adjustVolume(direction, AudioManager.FLAG_SHOW_UI); + controller.adjustVolume(direction, C.VOLUME_FLAG_SHOW_UI); PollingCheck.waitFor( VOLUME_CHANGE_TIMEOUT_MS, () -> targetVolume == audioManager.getStreamVolume(stream)); diff --git a/libraries/test_session_current/src/androidTest/java/androidx/media3/session/MediaSessionCompatCallbackWithMediaControllerTest.java b/libraries/test_session_current/src/androidTest/java/androidx/media3/session/MediaSessionCompatCallbackWithMediaControllerTest.java index b16847b8a8..95b4c06bdc 100644 --- a/libraries/test_session_current/src/androidTest/java/androidx/media3/session/MediaSessionCompatCallbackWithMediaControllerTest.java +++ b/libraries/test_session_current/src/androidTest/java/androidx/media3/session/MediaSessionCompatCallbackWithMediaControllerTest.java @@ -529,12 +529,13 @@ public class MediaSessionCompatCallbackWithMediaControllerTest { int maxVolume = 100; int currentVolume = 23; int volumeControlType = VolumeProviderCompat.VOLUME_CONTROL_ABSOLUTE; + int volumeFlags = C.VOLUME_FLAG_SHOW_UI; TestVolumeProvider volumeProvider = new TestVolumeProvider(volumeControlType, maxVolume, currentVolume); session.setPlaybackToRemote(volumeProvider); RemoteMediaController controller = createControllerAndWaitConnection(); - controller.decreaseDeviceVolume(); + controller.decreaseDeviceVolume(volumeFlags); assertThat(volumeProvider.latch.await(TIMEOUT_MS, MILLISECONDS)).isTrue(); assertThat(volumeProvider.adjustVolumeCalled).isTrue(); assertThat(volumeProvider.direction).isEqualTo(AudioManager.ADJUST_LOWER); @@ -554,12 +555,14 @@ public class MediaSessionCompatCallbackWithMediaControllerTest { if (maxVolume <= minVolume) { return; } + int volumeFlags = C.VOLUME_FLAG_SHOW_UI | C.VOLUME_FLAG_VIBRATE; + session.setPlaybackToLocal(stream); RemoteMediaController controller = createControllerAndWaitConnection(); int originalVolume = audioManager.getStreamVolume(stream); int targetVolume = originalVolume == minVolume ? originalVolume + 1 : originalVolume - 1; - controller.setDeviceVolume(targetVolume); + controller.setDeviceVolume(targetVolume, volumeFlags); PollingCheck.waitFor( VOLUME_CHANGE_TIMEOUT_MS, () -> targetVolume == audioManager.getStreamVolume(stream)); @@ -581,13 +584,15 @@ public class MediaSessionCompatCallbackWithMediaControllerTest { if (maxVolume <= minVolume) { return; } + int volumeFlags = C.VOLUME_FLAG_SHOW_UI | C.VOLUME_FLAG_VIBRATE; + session.setPlaybackToLocal(stream); RemoteMediaController controller = createControllerAndWaitConnection(); int originalVolume = audioManager.getStreamVolume(stream); audioManager.setStreamVolume(stream, minVolume, /* flags= */ 0); int targetVolume = minVolume + 1; - controller.increaseDeviceVolume(); + controller.increaseDeviceVolume(volumeFlags); PollingCheck.waitFor( VOLUME_CHANGE_TIMEOUT_MS, () -> targetVolume == audioManager.getStreamVolume(stream)); @@ -609,13 +614,15 @@ public class MediaSessionCompatCallbackWithMediaControllerTest { if (maxVolume <= minVolume) { return; } + int volumeFlags = C.VOLUME_FLAG_SHOW_UI | C.VOLUME_FLAG_VIBRATE; + session.setPlaybackToLocal(stream); RemoteMediaController controller = createControllerAndWaitConnection(); int originalVolume = audioManager.getStreamVolume(stream); audioManager.setStreamVolume(stream, maxVolume, /* flags= */ 0); int targetVolume = maxVolume - 1; - controller.decreaseDeviceVolume(); + controller.decreaseDeviceVolume(volumeFlags); PollingCheck.waitFor( VOLUME_CHANGE_TIMEOUT_MS, () -> targetVolume == audioManager.getStreamVolume(stream)); @@ -637,12 +644,14 @@ public class MediaSessionCompatCallbackWithMediaControllerTest { if (maxVolume <= minVolume) { return; } + int volumeFlags = C.VOLUME_FLAG_VIBRATE; + session.setPlaybackToLocal(stream); RemoteMediaController controller = createControllerAndWaitConnection(); boolean wasMuted = audioManager.isStreamMute(stream); audioManager.adjustStreamVolume(stream, AudioManager.ADJUST_UNMUTE, /* flags= */ 0); - controller.setDeviceMuted(true); + controller.setDeviceMuted(true, volumeFlags); PollingCheck.waitFor(VOLUME_CHANGE_TIMEOUT_MS, () -> audioManager.isStreamMute(stream)); // Set back to original mute state. diff --git a/libraries/test_session_current/src/androidTest/java/androidx/media3/session/MockPlayerTest.java b/libraries/test_session_current/src/androidTest/java/androidx/media3/session/MockPlayerTest.java index 2bf7dc8fa4..bbb59f68f2 100644 --- a/libraries/test_session_current/src/androidTest/java/androidx/media3/session/MockPlayerTest.java +++ b/libraries/test_session_current/src/androidTest/java/androidx/media3/session/MockPlayerTest.java @@ -17,6 +17,7 @@ package androidx.media3.session; import static com.google.common.truth.Truth.assertThat; +import androidx.media3.common.C; import androidx.media3.common.MediaItem; import androidx.media3.common.MediaMetadata; import androidx.media3.common.PlaybackParameters; @@ -437,6 +438,17 @@ public class MockPlayerTest { assertThat(player.deviceVolume).isEqualTo(testVolume); } + @Test + public void setDeviceVolumeWithFlags() { + int testVolume = 12; + int testVolumeFlags = C.VOLUME_FLAG_VIBRATE; + + player.setDeviceVolume(testVolume, testVolumeFlags); + + assertThat(player.hasMethodBeenCalled(MockPlayer.METHOD_SET_DEVICE_VOLUME_WITH_FLAGS)).isTrue(); + assertThat(player.deviceVolume).isEqualTo(testVolume); + } + @Test public void increaseDeviceVolume() { player.increaseDeviceVolume(); @@ -444,6 +456,15 @@ public class MockPlayerTest { assertThat(player.hasMethodBeenCalled(MockPlayer.METHOD_INCREASE_DEVICE_VOLUME)).isTrue(); } + @Test + public void increaseDeviceVolumeWithFlags() { + int testVolumeFlags = C.VOLUME_FLAG_VIBRATE | C.VOLUME_FLAG_PLAY_SOUND; + player.increaseDeviceVolume(testVolumeFlags); + + assertThat(player.hasMethodBeenCalled(MockPlayer.METHOD_INCREASE_DEVICE_VOLUME_WITH_FLAGS)) + .isTrue(); + } + @Test public void decreaseDeviceVolume() { player.decreaseDeviceVolume(); @@ -451,6 +472,15 @@ public class MockPlayerTest { assertThat(player.hasMethodBeenCalled(MockPlayer.METHOD_DECREASE_DEVICE_VOLUME)).isTrue(); } + @Test + public void decreaseDeviceVolumeWithFlags() { + int testVolumeFlags = C.VOLUME_FLAG_SHOW_UI; + player.decreaseDeviceVolume(testVolumeFlags); + + assertThat(player.hasMethodBeenCalled(MockPlayer.METHOD_DECREASE_DEVICE_VOLUME_WITH_FLAGS)) + .isTrue(); + } + @Test public void setDeviceMuted() { player.deviceMuted = false; @@ -461,6 +491,17 @@ public class MockPlayerTest { assertThat(player.deviceMuted).isTrue(); } + @Test + public void setDeviceMutedWithFlags() { + player.deviceMuted = false; + int testVolumeFlags = 0; + + player.setDeviceMuted(true, testVolumeFlags); + + assertThat(player.hasMethodBeenCalled(MockPlayer.METHOD_SET_DEVICE_MUTED_WITH_FLAGS)).isTrue(); + assertThat(player.deviceMuted).isTrue(); + } + @Test public void setTrackSelectionParameters() { TrackSelectionParameters trackSelectionParameters = diff --git a/libraries/test_session_current/src/main/java/androidx/media3/session/MediaControllerProviderService.java b/libraries/test_session_current/src/main/java/androidx/media3/session/MediaControllerProviderService.java index 31f1c8be13..1f5d9b5c16 100644 --- a/libraries/test_session_current/src/main/java/androidx/media3/session/MediaControllerProviderService.java +++ b/libraries/test_session_current/src/main/java/androidx/media3/session/MediaControllerProviderService.java @@ -523,7 +523,7 @@ public class MediaControllerProviderService extends Service { runOnHandler( () -> { MediaController controller = mediaControllerMap.get(controllerId); - controller.setDeviceVolume(value); + controller.setDeviceVolume(value, flags); }); } @@ -534,19 +534,19 @@ public class MediaControllerProviderService extends Service { MediaController controller = mediaControllerMap.get(controllerId); switch (direction) { case AudioManager.ADJUST_RAISE: - controller.increaseDeviceVolume(); + controller.increaseDeviceVolume(flags); break; case AudioManager.ADJUST_LOWER: - controller.decreaseDeviceVolume(); + controller.decreaseDeviceVolume(flags); break; case AudioManager.ADJUST_MUTE: - controller.setDeviceMuted(true); + controller.setDeviceMuted(true, flags); break; case AudioManager.ADJUST_UNMUTE: - controller.setDeviceMuted(false); + controller.setDeviceMuted(false, flags); break; case AudioManager.ADJUST_TOGGLE_MUTE: - controller.setDeviceMuted(controller.isDeviceMuted()); + controller.setDeviceMuted(controller.isDeviceMuted(), flags); break; default: throw new IllegalArgumentException("Unknown direction: " + direction); @@ -602,6 +602,16 @@ public class MediaControllerProviderService extends Service { }); } + @Override + public void setDeviceVolumeWithFlags(String controllerId, int volume, int flags) + throws RemoteException { + runOnHandler( + () -> { + MediaController controller = mediaControllerMap.get(controllerId); + controller.setDeviceVolume(volume, flags); + }); + } + @Override public void increaseDeviceVolume(String controllerId) throws RemoteException { runOnHandler( @@ -611,6 +621,16 @@ public class MediaControllerProviderService extends Service { }); } + @Override + public void increaseDeviceVolumeWithFlags(String controllerId, int flags) + throws RemoteException { + runOnHandler( + () -> { + MediaController controller = mediaControllerMap.get(controllerId); + controller.increaseDeviceVolume(flags); + }); + } + @Override public void decreaseDeviceVolume(String controllerId) throws RemoteException { runOnHandler( @@ -620,6 +640,16 @@ public class MediaControllerProviderService extends Service { }); } + @Override + public void decreaseDeviceVolumeWithFlags(String controllerId, int flags) + throws RemoteException { + runOnHandler( + () -> { + MediaController controller = mediaControllerMap.get(controllerId); + controller.decreaseDeviceVolume(flags); + }); + } + @Override public void setDeviceMuted(String controllerId, boolean muted) throws RemoteException { runOnHandler( @@ -629,6 +659,16 @@ public class MediaControllerProviderService extends Service { }); } + @Override + public void setDeviceMutedWithFlags(String controllerId, boolean muted, int flags) + throws RemoteException { + runOnHandler( + () -> { + MediaController controller = mediaControllerMap.get(controllerId); + controller.setDeviceMuted(muted, flags); + }); + } + @Override public void release(String controllerId) throws RemoteException { runOnHandler( diff --git a/libraries/test_session_current/src/main/java/androidx/media3/session/MediaSessionProviderService.java b/libraries/test_session_current/src/main/java/androidx/media3/session/MediaSessionProviderService.java index 4af259a69c..015b9dc512 100644 --- a/libraries/test_session_current/src/main/java/androidx/media3/session/MediaSessionProviderService.java +++ b/libraries/test_session_current/src/main/java/androidx/media3/session/MediaSessionProviderService.java @@ -662,6 +662,46 @@ public class MediaSessionProviderService extends Service { }); } + @Override + public void setDeviceVolume(String sessionId, int volume, int flags) throws RemoteException { + runOnHandler( + () -> { + MediaSession session = sessionMap.get(sessionId); + MockPlayer player = (MockPlayer) session.getPlayer(); + player.setDeviceVolume(volume, flags); + }); + } + + @Override + public void decreaseDeviceVolume(String sessionId, int flags) throws RemoteException { + runOnHandler( + () -> { + MediaSession session = sessionMap.get(sessionId); + MockPlayer player = (MockPlayer) session.getPlayer(); + player.decreaseDeviceVolume(flags); + }); + } + + @Override + public void increaseDeviceVolume(String sessionId, int flags) throws RemoteException { + runOnHandler( + () -> { + MediaSession session = sessionMap.get(sessionId); + MockPlayer player = (MockPlayer) session.getPlayer(); + player.increaseDeviceVolume(flags); + }); + } + + @Override + public void setDeviceMuted(String sessionId, boolean muted, int flags) throws RemoteException { + runOnHandler( + () -> { + MediaSession session = sessionMap.get(sessionId); + MockPlayer player = (MockPlayer) session.getPlayer(); + player.setDeviceMuted(muted, flags); + }); + } + @Override public void setCurrentAdIndexInAdGroup(String sessionId, int currentAdIndexInAdGroup) throws RemoteException { @@ -874,7 +914,6 @@ public class MediaSessionProviderService extends Service { MediaSession session = sessionMap.get(sessionId); MockPlayer player = (MockPlayer) session.getPlayer(); player.setVolume(volume); - player.notifyVolumeChanged(); }); } @@ -979,36 +1018,21 @@ public class MediaSessionProviderService extends Service { } @Override - public void notifyDeviceVolumeChanged(String sessionId, int volume, boolean muted) - throws RemoteException { + public void notifyVolumeChanged(String sessionId) throws RemoteException { runOnHandler( () -> { MediaSession session = sessionMap.get(sessionId); MockPlayer player = (MockPlayer) session.getPlayer(); - player.deviceVolume = volume; - player.deviceMuted = muted; - player.notifyDeviceVolumeChanged(); + player.notifyVolumeChanged(); }); } @Override - public void decreaseDeviceVolume(String sessionId) throws RemoteException { + public void notifyDeviceVolumeChanged(String sessionId) throws RemoteException { runOnHandler( () -> { MediaSession session = sessionMap.get(sessionId); MockPlayer player = (MockPlayer) session.getPlayer(); - player.decreaseDeviceVolume(); - player.notifyDeviceVolumeChanged(); - }); - } - - @Override - public void increaseDeviceVolume(String sessionId) throws RemoteException { - runOnHandler( - () -> { - MediaSession session = sessionMap.get(sessionId); - MockPlayer player = (MockPlayer) session.getPlayer(); - player.increaseDeviceVolume(); player.notifyDeviceVolumeChanged(); }); } diff --git a/libraries/test_session_current/src/main/java/androidx/media3/session/MockPlayer.java b/libraries/test_session_current/src/main/java/androidx/media3/session/MockPlayer.java index 9373a007bf..8696af0168 100644 --- a/libraries/test_session_current/src/main/java/androidx/media3/session/MockPlayer.java +++ b/libraries/test_session_current/src/main/java/androidx/media3/session/MockPlayer.java @@ -68,7 +68,9 @@ public class MockPlayer implements Player { METHOD_ADD_MEDIA_ITEMS_WITH_INDEX, METHOD_CLEAR_MEDIA_ITEMS, METHOD_DECREASE_DEVICE_VOLUME, + METHOD_DECREASE_DEVICE_VOLUME_WITH_FLAGS, METHOD_INCREASE_DEVICE_VOLUME, + METHOD_INCREASE_DEVICE_VOLUME_WITH_FLAGS, METHOD_MOVE_MEDIA_ITEM, METHOD_MOVE_MEDIA_ITEMS, METHOD_PAUSE, @@ -88,7 +90,9 @@ public class MockPlayer implements Player { METHOD_SEEK_TO_PREVIOUS_MEDIA_ITEM, METHOD_SEEK_TO_WITH_MEDIA_ITEM_INDEX, METHOD_SET_DEVICE_MUTED, + METHOD_SET_DEVICE_MUTED_WITH_FLAGS, METHOD_SET_DEVICE_VOLUME, + METHOD_SET_DEVICE_VOLUME_WITH_FLAGS, METHOD_SET_MEDIA_ITEM, METHOD_SET_MEDIA_ITEM_WITH_RESET_POSITION, METHOD_SET_MEDIA_ITEM_WITH_START_POSITION, @@ -191,6 +195,14 @@ public class MockPlayer implements Player { public static final int METHOD_SET_VOLUME = 40; /** Maps to {@link Player#stop()}. */ public static final int METHOD_STOP = 41; + /** Maps to {@link Player#decreaseDeviceVolume(int)}. */ + public static final int METHOD_DECREASE_DEVICE_VOLUME_WITH_FLAGS = 42; + /** Maps to {@link Player#increaseDeviceVolume(int)}. */ + public static final int METHOD_INCREASE_DEVICE_VOLUME_WITH_FLAGS = 43; + /** Maps to {@link Player#setDeviceMuted(boolean, int)}. */ + public static final int METHOD_SET_DEVICE_MUTED_WITH_FLAGS = 44; + /** Maps to {@link Player#setDeviceVolume(int, int)}. */ + public static final int METHOD_SET_DEVICE_VOLUME_WITH_FLAGS = 45; private final boolean changePlayerStateWithTransportControl; private final Looper applicationLooper; @@ -648,30 +660,58 @@ public class MockPlayer implements Player { return deviceMuted; } + @Deprecated @Override public void setDeviceVolume(int volume) { deviceVolume = volume; checkNotNull(conditionVariables.get(METHOD_SET_DEVICE_VOLUME)).open(); } + @Override + public void setDeviceVolume(int volume, @C.VolumeFlags int flags) { + deviceVolume = volume; + checkNotNull(conditionVariables.get(METHOD_SET_DEVICE_VOLUME_WITH_FLAGS)).open(); + } + + @Deprecated @Override public void increaseDeviceVolume() { deviceVolume += 1; checkNotNull(conditionVariables.get(METHOD_INCREASE_DEVICE_VOLUME)).open(); } + @Override + public void increaseDeviceVolume(@C.VolumeFlags int flags) { + deviceVolume += 1; + checkNotNull(conditionVariables.get(METHOD_INCREASE_DEVICE_VOLUME_WITH_FLAGS)).open(); + } + + @Deprecated @Override public void decreaseDeviceVolume() { deviceVolume -= 1; checkNotNull(conditionVariables.get(METHOD_DECREASE_DEVICE_VOLUME)).open(); } + @Override + public void decreaseDeviceVolume(@C.VolumeFlags int flags) { + deviceVolume -= 1; + checkNotNull(conditionVariables.get(METHOD_DECREASE_DEVICE_VOLUME_WITH_FLAGS)).open(); + } + + @Deprecated @Override public void setDeviceMuted(boolean muted) { deviceMuted = muted; checkNotNull(conditionVariables.get(METHOD_SET_DEVICE_MUTED)).open(); } + @Override + public void setDeviceMuted(boolean muted, @C.VolumeFlags int flags) { + deviceMuted = muted; + checkNotNull(conditionVariables.get(METHOD_SET_DEVICE_MUTED_WITH_FLAGS)).open(); + } + @Override public void setPlayWhenReady(boolean playWhenReady) { this.playWhenReady = playWhenReady; @@ -1329,7 +1369,9 @@ public class MockPlayer implements Player { .put(METHOD_ADD_MEDIA_ITEMS_WITH_INDEX, new ConditionVariable()) .put(METHOD_CLEAR_MEDIA_ITEMS, new ConditionVariable()) .put(METHOD_DECREASE_DEVICE_VOLUME, new ConditionVariable()) + .put(METHOD_DECREASE_DEVICE_VOLUME_WITH_FLAGS, new ConditionVariable()) .put(METHOD_INCREASE_DEVICE_VOLUME, new ConditionVariable()) + .put(METHOD_INCREASE_DEVICE_VOLUME_WITH_FLAGS, new ConditionVariable()) .put(METHOD_MOVE_MEDIA_ITEM, new ConditionVariable()) .put(METHOD_MOVE_MEDIA_ITEMS, new ConditionVariable()) .put(METHOD_PAUSE, new ConditionVariable()) @@ -1349,7 +1391,9 @@ public class MockPlayer implements Player { .put(METHOD_SEEK_TO_PREVIOUS_MEDIA_ITEM, new ConditionVariable()) .put(METHOD_SEEK_TO_WITH_MEDIA_ITEM_INDEX, new ConditionVariable()) .put(METHOD_SET_DEVICE_MUTED, new ConditionVariable()) + .put(METHOD_SET_DEVICE_MUTED_WITH_FLAGS, new ConditionVariable()) .put(METHOD_SET_DEVICE_VOLUME, new ConditionVariable()) + .put(METHOD_SET_DEVICE_VOLUME_WITH_FLAGS, new ConditionVariable()) .put(METHOD_SET_MEDIA_ITEM, new ConditionVariable()) .put(METHOD_SET_MEDIA_ITEM_WITH_RESET_POSITION, new ConditionVariable()) .put(METHOD_SET_MEDIA_ITEM_WITH_START_POSITION, new ConditionVariable()) diff --git a/libraries/test_session_current/src/main/java/androidx/media3/session/RemoteMediaController.java b/libraries/test_session_current/src/main/java/androidx/media3/session/RemoteMediaController.java index 0d8c990016..c3bf2b6600 100644 --- a/libraries/test_session_current/src/main/java/androidx/media3/session/RemoteMediaController.java +++ b/libraries/test_session_current/src/main/java/androidx/media3/session/RemoteMediaController.java @@ -29,6 +29,7 @@ import android.os.Bundle; import android.os.IBinder; import android.os.RemoteException; import androidx.annotation.Nullable; +import androidx.media3.common.C; import androidx.media3.common.MediaItem; import androidx.media3.common.MediaMetadata; import androidx.media3.common.PlaybackParameters; @@ -249,18 +250,34 @@ public class RemoteMediaController { binder.setDeviceVolume(controllerId, volume); } + public void setDeviceVolume(int volume, @C.VolumeFlags int flags) throws RemoteException { + binder.setDeviceVolumeWithFlags(controllerId, volume, flags); + } + public void increaseDeviceVolume() throws RemoteException { binder.increaseDeviceVolume(controllerId); } + public void increaseDeviceVolume(@C.VolumeFlags int flags) throws RemoteException { + binder.increaseDeviceVolumeWithFlags(controllerId, flags); + } + public void decreaseDeviceVolume() throws RemoteException { binder.decreaseDeviceVolume(controllerId); } + public void decreaseDeviceVolume(@C.VolumeFlags int flags) throws RemoteException { + binder.decreaseDeviceVolumeWithFlags(controllerId, flags); + } + public void setDeviceMuted(boolean muted) throws RemoteException { binder.setDeviceMuted(controllerId, muted); } + public void setDeviceMuted(boolean muted, @C.VolumeFlags int flags) throws RemoteException { + binder.setDeviceMutedWithFlags(controllerId, muted, flags); + } + public SessionResult sendCustomCommand(SessionCommand command, Bundle args) throws RemoteException { Bundle result = binder.sendCustomCommand(controllerId, command.toBundle(), args); diff --git a/libraries/test_session_current/src/main/java/androidx/media3/session/RemoteMediaSession.java b/libraries/test_session_current/src/main/java/androidx/media3/session/RemoteMediaSession.java index 392a382129..eb31257ad5 100644 --- a/libraries/test_session_current/src/main/java/androidx/media3/session/RemoteMediaSession.java +++ b/libraries/test_session_current/src/main/java/androidx/media3/session/RemoteMediaSession.java @@ -69,6 +69,7 @@ import android.os.RemoteException; import android.support.v4.media.session.MediaSessionCompat; import androidx.annotation.Nullable; import androidx.media3.common.AudioAttributes; +import androidx.media3.common.C; import androidx.media3.common.DeviceInfo; import androidx.media3.common.MediaMetadata; import androidx.media3.common.PlaybackException; @@ -90,8 +91,8 @@ import java.util.List; import java.util.concurrent.CountDownLatch; /** - * Represents remote {@link MediaSession} in the service app's MediaSessionProviderService. Users - * can run {@link MediaSession} methods remotely with this object. + * Represents remote {@link MediaSession} in the service app's {@link MediaSessionProviderService}. + * Users can run {@link MediaSession} methods remotely with this object. */ public class RemoteMediaSession { private static final String TAG = "RemoteMediaSession"; @@ -284,6 +285,22 @@ public class RemoteMediaSession { binder.setVolume(sessionId, volume); } + public void setDeviceVolume(int volume, @C.VolumeFlags int flags) throws RemoteException { + binder.setDeviceVolume(sessionId, volume, flags); + } + + public void decreaseDeviceVolume(@C.VolumeFlags int flags) throws RemoteException { + binder.decreaseDeviceVolume(sessionId, flags); + } + + public void increaseDeviceVolume(@C.VolumeFlags int flags) throws RemoteException { + binder.increaseDeviceVolume(sessionId, flags); + } + + public void setDeviceMuted(boolean muted, @C.VolumeFlags int flags) throws RemoteException { + binder.setDeviceMuted(sessionId, muted, flags); + } + public void notifyPlayWhenReadyChanged( boolean playWhenReady, @Player.PlaybackSuppressionReason int reason) throws RemoteException { @@ -397,16 +414,12 @@ public class RemoteMediaSession { return binder.surfaceExists(sessionId); } - public void notifyDeviceVolumeChanged(int volume, boolean muted) throws RemoteException { - binder.notifyDeviceVolumeChanged(sessionId, volume, muted); + public void notifyDeviceVolumeChanged() throws RemoteException { + binder.notifyDeviceVolumeChanged(sessionId); } - public void decreaseDeviceVolume() throws RemoteException { - binder.decreaseDeviceVolume(sessionId); - } - - public void increaseDeviceVolume() throws RemoteException { - binder.increaseDeviceVolume(sessionId); + public void notifyVolumeChanged() throws RemoteException { + binder.notifyVolumeChanged(sessionId); } public void notifyCuesChanged(CueGroup cueGroup) throws RemoteException { diff --git a/libraries/test_utils/src/main/java/androidx/media3/test/utils/StubPlayer.java b/libraries/test_utils/src/main/java/androidx/media3/test/utils/StubPlayer.java index 324d5d74ea..d6d6ed9c9d 100644 --- a/libraries/test_utils/src/main/java/androidx/media3/test/utils/StubPlayer.java +++ b/libraries/test_utils/src/main/java/androidx/media3/test/utils/StubPlayer.java @@ -23,6 +23,7 @@ import android.view.TextureView; import androidx.annotation.Nullable; import androidx.media3.common.AudioAttributes; import androidx.media3.common.BasePlayer; +import androidx.media3.common.C; import androidx.media3.common.DeviceInfo; import androidx.media3.common.MediaItem; import androidx.media3.common.MediaMetadata; @@ -370,23 +371,59 @@ public class StubPlayer extends BasePlayer { throw new UnsupportedOperationException(); } + /** + * @deprecated Use {@link #setDeviceVolume(int, int)} instead. + */ + @Deprecated @Override public void setDeviceVolume(int volume) { throw new UnsupportedOperationException(); } + @Override + public void setDeviceVolume(int volume, @C.VolumeFlags int flags) { + throw new UnsupportedOperationException(); + } + + /** + * @deprecated Use {@link #increaseDeviceVolume(int)} instead. + */ + @Deprecated @Override public void increaseDeviceVolume() { throw new UnsupportedOperationException(); } + @Override + public void increaseDeviceVolume(@C.VolumeFlags int flags) { + throw new UnsupportedOperationException(); + } + + /** + * @deprecated Use {@link #decreaseDeviceVolume(int)} instead. + */ + @Deprecated @Override public void decreaseDeviceVolume() { throw new UnsupportedOperationException(); } + @Override + public void decreaseDeviceVolume(@C.VolumeFlags int flags) { + throw new UnsupportedOperationException(); + } + + /** + * @deprecated Use {@link #setDeviceMuted(boolean, int)} instead. + */ + @Deprecated @Override public void setDeviceMuted(boolean muted) { throw new UnsupportedOperationException(); } + + @Override + public void setDeviceMuted(boolean muted, @C.VolumeFlags int flags) { + throw new UnsupportedOperationException(); + } }