Allow ExoPlayer to opt into volume device control, forbidden by default

PiperOrigin-RevId: 532136692
(cherry picked from commit 1c6b894e8880480918babaf0a6f6b2038faf2e81)
This commit is contained in:
jbibik 2023-05-15 17:30:50 +01:00 committed by Tofunmi Adigun-Hameed
parent 7f1c1185e7
commit 27becc028d
5 changed files with 269 additions and 47 deletions

View File

@ -47,9 +47,17 @@
objects that are dispatched by the dispatcher.
* Rename `ExoTrackSelection.blacklist` to `excludeTrack` and
`isBlacklisted` to `isTrackExcluded`.
* Deprecate `Player.COMMAND_GET_MEDIA_ITEMS_METADATA` and
`COMMAND_SET_MEDIA_ITEMS_METADATA`. Use `COMMAND_GET_METADATA` and
`COMMAND_SET_PLAYLIST_METADATA` instead.
* Add commands to Player:
* `COMMAND_GET_METADATA`
* `COMMAND_SET_PLAYLIST_METADATA`
* `COMMAND_SET_DEVICE_VOLUME_WITH_FLAGS`
* `COMMAND_ADJUST_DEVICE_VOLUME_WITH_FLAGS`
* Add overloaded methods to Player which allow users to specify volume
flags:
* `void setDeviceVolume(int, int)`
* `void increaseDeviceVolume(int)`
* `void decreaseDeviceVolume(int)`
* `void setDeviceMuted(boolean, int)`
* Add `Buffer.isLastSample()` that denotes if `Buffer` contains flag
`C.BUFFER_FLAG_LAST_SAMPLE`.
* Fix issue where last frame may not be rendered if the last sample with
@ -64,13 +72,16 @@
* Fix parsing of H.265 SPS in MPEG-TS files by re-using the parsing logic
already used by RTSP and MP4 extractors
([#303](https://github.com/androidx/media/issues/303)).
* ExoPlayer:
* Allow ExoPlayer to have control of device volume methods only if
explicitly opted in. Use
`ExoPlayer.Builder.setDeviceVolumeControlEnabled` to have access to:
* `getDeviceVolume()`
* `isDeviceMuted()`
* `setDeviceVolume(int)` and `setDeviceVolume(int, int)`
* `increaseDeviceVolume(int)` and `increaseDeviceVolume(int, int)`
* `decreaseDeviceVolume(int)` and `decreaseDeviceVolume(int, int)`
* Session:
* 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)`
* Fix issue where `MediaController` doesn't update its available commands
when connected to a legacy `MediaSessionCompat` that updates its
actions.

View File

@ -479,6 +479,7 @@ public interface ExoPlayer extends Player {
@C.WakeMode /* package */ int wakeMode;
/* package */ boolean handleAudioBecomingNoisy;
/* package */ boolean skipSilenceEnabled;
/* package */ boolean deviceVolumeControlEnabled;
@C.VideoScalingMode /* package */ int videoScalingMode;
@C.VideoChangeFrameRateStrategy /* package */ int videoChangeFrameRateStrategy;
/* package */ boolean useLazyPreparation;
@ -918,6 +919,21 @@ public interface ExoPlayer extends Player {
return this;
}
/**
* Sets whether the player is allowed to set, increase, decrease or mute device volume.
*
* @param deviceVolumeControlEnabled Whether controlling device volume is enabled.
* @return This builder.
* @throws IllegalStateException If {@link #build()} has already been called.
*/
@CanIgnoreReturnValue
@UnstableApi
public Builder setDeviceVolumeControlEnabled(boolean deviceVolumeControlEnabled) {
checkState(!buildCalled);
this.deviceVolumeControlEnabled = deviceVolumeControlEnabled;
return this;
}
/**
* Sets the {@link C.VideoScalingMode} that will be used by the player.
*

View File

@ -168,7 +168,7 @@ import java.util.concurrent.TimeoutException;
private final FrameMetadataListener frameMetadataListener;
private final AudioBecomingNoisyManager audioBecomingNoisyManager;
private final AudioFocusManager audioFocusManager;
private final StreamVolumeManager streamVolumeManager;
@Nullable private final StreamVolumeManager streamVolumeManager;
private final WakeLockManager wakeLockManager;
private final WifiLockManager wifiLockManager;
private final long detachSurfaceTimeoutMs;
@ -228,6 +228,7 @@ import java.util.concurrent.TimeoutException;
private long maskingWindowPositionMs;
@SuppressLint("HandlerLeak")
@SuppressWarnings("deprecation") // Control flow for old volume commands
public ExoPlayerImpl(ExoPlayer.Builder builder, @Nullable Player wrappingPlayer) {
constructorFinished = new ConditionVariable();
try {
@ -306,17 +307,17 @@ import java.util.concurrent.TimeoutException;
COMMAND_GET_TRACKS,
COMMAND_GET_AUDIO_ATTRIBUTES,
COMMAND_GET_VOLUME,
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)
.addIf(
COMMAND_SET_TRACK_SELECTION_PARAMETERS, trackSelector.isSetParametersSupported())
.addIf(COMMAND_GET_DEVICE_VOLUME, builder.deviceVolumeControlEnabled)
.addIf(COMMAND_SET_DEVICE_VOLUME, builder.deviceVolumeControlEnabled)
.addIf(COMMAND_SET_DEVICE_VOLUME_WITH_FLAGS, builder.deviceVolumeControlEnabled)
.addIf(COMMAND_ADJUST_DEVICE_VOLUME, builder.deviceVolumeControlEnabled)
.addIf(COMMAND_ADJUST_DEVICE_VOLUME_WITH_FLAGS, builder.deviceVolumeControlEnabled)
.build();
availableCommands =
new Commands.Builder()
@ -381,9 +382,13 @@ import java.util.concurrent.TimeoutException;
audioBecomingNoisyManager.setEnabled(builder.handleAudioBecomingNoisy);
audioFocusManager = new AudioFocusManager(builder.context, eventHandler, componentListener);
audioFocusManager.setAudioAttributes(builder.handleAudioFocus ? audioAttributes : null);
streamVolumeManager =
new StreamVolumeManager(builder.context, eventHandler, componentListener);
streamVolumeManager.setStreamType(Util.getStreamTypeForAudioUsage(audioAttributes.usage));
if (builder.deviceVolumeControlEnabled) {
streamVolumeManager =
new StreamVolumeManager(builder.context, eventHandler, componentListener);
streamVolumeManager.setStreamType(Util.getStreamTypeForAudioUsage(audioAttributes.usage));
} else {
streamVolumeManager = null;
}
wakeLockManager = new WakeLockManager(builder.context);
wakeLockManager.setEnabled(builder.wakeMode != C.WAKE_MODE_NONE);
wifiLockManager = new WifiLockManager(builder.context);
@ -999,7 +1004,9 @@ import java.util.concurrent.TimeoutException;
keepSessionIdAudioTrack = null;
}
audioBecomingNoisyManager.setEnabled(false);
streamVolumeManager.release();
if (streamVolumeManager != null) {
streamVolumeManager.release();
}
wakeLockManager.setStayAwake(false);
wifiLockManager.setStayAwake(false);
audioFocusManager.release();
@ -1421,7 +1428,10 @@ import java.util.concurrent.TimeoutException;
if (!Util.areEqual(this.audioAttributes, newAudioAttributes)) {
this.audioAttributes = newAudioAttributes;
sendRendererMessage(TRACK_TYPE_AUDIO, MSG_SET_AUDIO_ATTRIBUTES, newAudioAttributes);
streamVolumeManager.setStreamType(Util.getStreamTypeForAudioUsage(newAudioAttributes.usage));
if (streamVolumeManager != null) {
streamVolumeManager.setStreamType(
Util.getStreamTypeForAudioUsage(newAudioAttributes.usage));
}
// Queue event only and flush after updating playWhenReady in case both events are triggered.
listeners.queueEvent(
EVENT_AUDIO_ATTRIBUTES_CHANGED,
@ -1703,13 +1713,21 @@ import java.util.concurrent.TimeoutException;
@Override
public int getDeviceVolume() {
verifyApplicationThread();
return streamVolumeManager.getVolume();
if (streamVolumeManager != null) {
return streamVolumeManager.getVolume();
} else {
return 0;
}
}
@Override
public boolean isDeviceMuted() {
verifyApplicationThread();
return streamVolumeManager.isMuted();
if (streamVolumeManager != null) {
return streamVolumeManager.isMuted();
} else {
return false;
}
}
/**
@ -1719,13 +1737,17 @@ import java.util.concurrent.TimeoutException;
@Override
public void setDeviceVolume(int volume) {
verifyApplicationThread();
streamVolumeManager.setVolume(volume, C.VOLUME_FLAG_SHOW_UI);
if (streamVolumeManager != null) {
streamVolumeManager.setVolume(volume, C.VOLUME_FLAG_SHOW_UI);
}
}
@Override
public void setDeviceVolume(int volume, @C.VolumeFlags int flags) {
verifyApplicationThread();
streamVolumeManager.setVolume(volume, flags);
if (streamVolumeManager != null) {
streamVolumeManager.setVolume(volume, flags);
}
}
/**
@ -1735,13 +1757,17 @@ import java.util.concurrent.TimeoutException;
@Override
public void increaseDeviceVolume() {
verifyApplicationThread();
streamVolumeManager.increaseVolume(C.VOLUME_FLAG_SHOW_UI);
if (streamVolumeManager != null) {
streamVolumeManager.increaseVolume(C.VOLUME_FLAG_SHOW_UI);
}
}
@Override
public void increaseDeviceVolume(@C.VolumeFlags int flags) {
verifyApplicationThread();
streamVolumeManager.increaseVolume(flags);
if (streamVolumeManager != null) {
streamVolumeManager.increaseVolume(flags);
}
}
/**
@ -1751,13 +1777,17 @@ import java.util.concurrent.TimeoutException;
@Override
public void decreaseDeviceVolume() {
verifyApplicationThread();
streamVolumeManager.decreaseVolume(C.VOLUME_FLAG_SHOW_UI);
if (streamVolumeManager != null) {
streamVolumeManager.decreaseVolume(C.VOLUME_FLAG_SHOW_UI);
}
}
@Override
public void decreaseDeviceVolume(@C.VolumeFlags int flags) {
verifyApplicationThread();
streamVolumeManager.decreaseVolume(flags);
if (streamVolumeManager != null) {
streamVolumeManager.decreaseVolume(flags);
}
}
/**
@ -1767,13 +1797,17 @@ import java.util.concurrent.TimeoutException;
@Override
public void setDeviceMuted(boolean muted) {
verifyApplicationThread();
streamVolumeManager.setMuted(muted, C.VOLUME_FLAG_SHOW_UI);
if (streamVolumeManager != null) {
streamVolumeManager.setMuted(muted, C.VOLUME_FLAG_SHOW_UI);
}
}
@Override
public void setDeviceMuted(boolean muted, @C.VolumeFlags int flags) {
verifyApplicationThread();
streamVolumeManager.setMuted(muted, flags);
if (streamVolumeManager != null) {
streamVolumeManager.setMuted(muted, flags);
}
}
@Override
@ -2797,10 +2831,10 @@ import java.util.concurrent.TimeoutException;
}
}
private static DeviceInfo createDeviceInfo(StreamVolumeManager streamVolumeManager) {
private static DeviceInfo createDeviceInfo(@Nullable StreamVolumeManager streamVolumeManager) {
return new DeviceInfo.Builder(DeviceInfo.PLAYBACK_TYPE_LOCAL)
.setMinVolume(streamVolumeManager.getMinVolume())
.setMaxVolume(streamVolumeManager.getMaxVolume())
.setMinVolume(streamVolumeManager != null ? streamVolumeManager.getMinVolume() : 0)
.setMaxVolume(streamVolumeManager != null ? streamVolumeManager.getMaxVolume() : 0)
.build();
}

View File

@ -100,6 +100,7 @@ import androidx.annotation.Nullable;
import androidx.media3.common.AdPlaybackState;
import androidx.media3.common.AudioAttributes;
import androidx.media3.common.C;
import androidx.media3.common.DeviceInfo;
import androidx.media3.common.Format;
import androidx.media3.common.MediaItem;
import androidx.media3.common.MediaMetadata;
@ -9155,6 +9156,7 @@ public final class ExoPlayerTest {
player.release();
}
@SuppressWarnings("deprecation") // Checking old volume commands
@Test
public void isCommandAvailable_isTrueForAvailableCommands() {
ExoPlayer player = new TestExoPlayerBuilder(context).build();
@ -9184,10 +9186,7 @@ public final class ExoPlayerTest {
assertThat(player.isCommandAvailable(COMMAND_SET_MEDIA_ITEM)).isTrue();
assertThat(player.isCommandAvailable(COMMAND_GET_AUDIO_ATTRIBUTES)).isTrue();
assertThat(player.isCommandAvailable(COMMAND_GET_VOLUME)).isTrue();
assertThat(player.isCommandAvailable(COMMAND_GET_DEVICE_VOLUME)).isTrue();
assertThat(player.isCommandAvailable(COMMAND_SET_VOLUME)).isTrue();
assertThat(player.isCommandAvailable(COMMAND_SET_DEVICE_VOLUME)).isTrue();
assertThat(player.isCommandAvailable(COMMAND_ADJUST_DEVICE_VOLUME)).isTrue();
assertThat(player.isCommandAvailable(COMMAND_SET_VIDEO_SURFACE)).isTrue();
assertThat(player.isCommandAvailable(COMMAND_GET_TEXT)).isTrue();
assertThat(player.isCommandAvailable(COMMAND_SET_TRACK_SELECTION_PARAMETERS)).isTrue();
@ -9195,6 +9194,33 @@ public final class ExoPlayerTest {
assertThat(player.isCommandAvailable(COMMAND_RELEASE)).isTrue();
}
@SuppressWarnings("deprecation") // Checking old volume commands
@Test
public void isCommandAvailable_withDeviceVolumeControlEnabled_isTrueForDeviceVolumeCommands() {
ExoPlayer player =
new TestExoPlayerBuilder(context).setDeviceVolumeControlEnabled(true).build();
assertThat(player.isCommandAvailable(COMMAND_GET_DEVICE_VOLUME)).isTrue();
assertThat(player.isCommandAvailable(COMMAND_SET_DEVICE_VOLUME)).isTrue();
assertThat(player.isCommandAvailable(COMMAND_ADJUST_DEVICE_VOLUME)).isTrue();
assertThat(player.isCommandAvailable(COMMAND_SET_DEVICE_VOLUME_WITH_FLAGS)).isTrue();
assertThat(player.isCommandAvailable(COMMAND_ADJUST_DEVICE_VOLUME_WITH_FLAGS)).isTrue();
}
@SuppressWarnings("deprecation") // Checking old volume commands
@Test
public void
isCommandAvailable_withoutDeviceVolumeControlEnabled_isFalseForDeviceVolumeCommands() {
ExoPlayer player =
new TestExoPlayerBuilder(context).setDeviceVolumeControlEnabled(false).build();
assertThat(player.isCommandAvailable(COMMAND_GET_DEVICE_VOLUME)).isFalse();
assertThat(player.isCommandAvailable(COMMAND_SET_DEVICE_VOLUME)).isFalse();
assertThat(player.isCommandAvailable(COMMAND_ADJUST_DEVICE_VOLUME)).isFalse();
assertThat(player.isCommandAvailable(COMMAND_SET_DEVICE_VOLUME_WITH_FLAGS)).isFalse();
assertThat(player.isCommandAvailable(COMMAND_ADJUST_DEVICE_VOLUME_WITH_FLAGS)).isFalse();
}
@Test
public void isCommandAvailable_duringAd_isFalseForSeekCommands() throws Exception {
AdPlaybackState adPlaybackState =
@ -9529,7 +9555,9 @@ public final class ExoPlayerTest {
Player.Commands defaultCommands = createWithDefaultCommands();
Player.Commands commandsWithSeekToNextWindow =
createWithDefaultCommands(COMMAND_SEEK_TO_NEXT_MEDIA_ITEM, COMMAND_SEEK_TO_NEXT);
Player.Commands emptyTimelineCommands = createWithDefaultCommands(/* isTimelineEmpty= */ true);
Player.Commands emptyTimelineCommands =
createWithDefaultCommands(
/* isTimelineEmpty= */ true, /* allowDeviceVolumeControl= */ false);
Player.Listener mockListener = mock(Player.Listener.class);
ExoPlayer player = new TestExoPlayerBuilder(context).build();
player.addListener(mockListener);
@ -9557,7 +9585,9 @@ public final class ExoPlayerTest {
Player.Commands defaultCommands = createWithDefaultCommands();
Player.Commands commandsWithSeekToPreviousWindow =
createWithDefaultCommands(COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM);
Player.Commands emptyTimelineCommands = createWithDefaultCommands(/* isTimelineEmpty= */ true);
Player.Commands emptyTimelineCommands =
createWithDefaultCommands(
/* isTimelineEmpty= */ true, /* allowDeviceVolumeControl= */ false);
Player.Listener mockListener = mock(Player.Listener.class);
ExoPlayer player = new TestExoPlayerBuilder(context).build();
player.addListener(mockListener);
@ -12323,7 +12353,9 @@ public final class ExoPlayerTest {
@Test
public void releaseAfterVolumeChanges_triggerPendingDeviceVolumeEventsInListener() {
ExoPlayer player =
new TestExoPlayerBuilder(ApplicationProvider.getApplicationContext()).build();
new TestExoPlayerBuilder(ApplicationProvider.getApplicationContext())
.setDeviceVolumeControlEnabled(true)
.build();
Player.Listener listener = mock(Player.Listener.class);
player.addListener(listener);
@ -12343,6 +12375,113 @@ public final class ExoPlayerTest {
verify(listener, atLeast(2)).onDeviceVolumeChanged(anyInt(), anyBoolean());
}
@Test
public void setDeviceMutedWithoutDeviceVolumeControl_noEffectDeviceRemainsUnmuted() {
ExoPlayer player =
new TestExoPlayerBuilder(ApplicationProvider.getApplicationContext())
.setDeviceVolumeControlEnabled(false)
.build();
Player.Listener listener = mock(Player.Listener.class);
player.addListener(listener);
player.setDeviceMuted(/* muted= */ true, /* flags= */ 0); // no volume control, no effect
boolean isActuallyMuted = player.isDeviceMuted();
player.release();
assertThat(isActuallyMuted).isFalse();
verify(listener, times(0)).onDeviceVolumeChanged(anyInt(), anyBoolean());
}
@Test
public void setDeviceMutedWithDeviceVolumeControl_deviceGetsMuted() {
ExoPlayer player =
new TestExoPlayerBuilder(ApplicationProvider.getApplicationContext())
.setDeviceVolumeControlEnabled(true)
.build();
Player.Listener listener = mock(Player.Listener.class);
player.addListener(listener);
player.setDeviceMuted(/* muted= */ true, /* flags= */ 0);
boolean isActuallyMuted = player.isDeviceMuted();
player.release();
assertThat(isActuallyMuted).isTrue();
verify(listener).onDeviceVolumeChanged(anyInt(), anyBoolean());
}
@Test
public void increaseDeviceVolumeWithoutDeviceVolumeControl_deviceVolumeUnchanged() {
ExoPlayer player =
new TestExoPlayerBuilder(ApplicationProvider.getApplicationContext())
.setDeviceVolumeControlEnabled(false)
.build();
Player.Listener listener = mock(Player.Listener.class);
player.addListener(listener);
player.increaseDeviceVolume(/* flags= */ 0); // no volume control, no effect
player.release();
verify(listener, times(0)).onDeviceVolumeChanged(anyInt(), anyBoolean());
}
@Test
public void decreaseDeviceVolumeWithoutDeviceVolumeControl_deviceVolumeUnchanged() {
ExoPlayer player =
new TestExoPlayerBuilder(ApplicationProvider.getApplicationContext())
.setDeviceVolumeControlEnabled(false)
.build();
Player.Listener listener = mock(Player.Listener.class);
player.addListener(listener);
player.decreaseDeviceVolume(/* flags= */ 0); // no volume control, no effect
player.release();
verify(listener, times(0)).onDeviceVolumeChanged(anyInt(), anyBoolean());
}
@Test
public void getDeviceVolumeWithoutDeviceVolumeControl_returnsZero() {
ExoPlayer player =
new TestExoPlayerBuilder(ApplicationProvider.getApplicationContext())
.setDeviceVolumeControlEnabled(false)
.build();
Player.Listener listener = mock(Player.Listener.class);
player.addListener(listener);
int initialDeviceVolume = player.getDeviceVolume();
player.setDeviceVolume(10, /* flags= */ 0);
int setDeviceVolumeAt10 = player.getDeviceVolume();
player.increaseDeviceVolume(/* flags= */ 0);
player.increaseDeviceVolume(/* flags= */ 0);
int setDeviceVolumeAt12 = player.getDeviceVolume();
player.decreaseDeviceVolume(/* flags= */ 0);
int setDeviceVolumeAt11 = player.getDeviceVolume();
player.release();
assertThat(initialDeviceVolume).isEqualTo(0);
assertThat(setDeviceVolumeAt10).isEqualTo(0);
assertThat(setDeviceVolumeAt12).isEqualTo(0);
assertThat(setDeviceVolumeAt11).isEqualTo(0);
verify(listener, times(0)).onDeviceVolumeChanged(anyInt(), anyBoolean());
}
@Test
public void getDeviceInfoWithoutDeviceVolumeControl_returnsZeroForMinMaxVolume() {
ExoPlayer player =
new TestExoPlayerBuilder(ApplicationProvider.getApplicationContext())
.setDeviceVolumeControlEnabled(false)
.build();
Player.Listener listener = mock(Player.Listener.class);
player.addListener(listener);
DeviceInfo deviceInfo = player.getDeviceInfo();
int minVolume = deviceInfo.minVolume;
int maxVolume = deviceInfo.maxVolume;
assertThat(minVolume).isEqualTo(0);
assertThat(maxVolume).isEqualTo(0);
}
@Test
public void loadControlBackBuffer_withInsufficientMemoryLimits_stillContinuesPlayback()
throws Exception {
@ -12482,8 +12621,11 @@ public final class ExoPlayerTest {
return false;
}
@SuppressWarnings("deprecation") // Control flow for the old volume commands
private static Player.Commands createWithDefaultCommands(
boolean isTimelineEmpty, @Player.Command int... additionalCommands) {
boolean isTimelineEmpty,
boolean allowDeviceVolumeControl,
@Player.Command int... additionalCommands) {
Player.Commands.Builder builder = new Player.Commands.Builder();
builder.addAll(
COMMAND_PLAY_PAUSE,
@ -12502,12 +12644,7 @@ public final class ExoPlayerTest {
COMMAND_SET_MEDIA_ITEM,
COMMAND_GET_AUDIO_ATTRIBUTES,
COMMAND_GET_VOLUME,
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,
@ -12516,13 +12653,22 @@ public final class ExoPlayerTest {
if (!isTimelineEmpty) {
builder.add(COMMAND_SEEK_TO_PREVIOUS);
}
if (allowDeviceVolumeControl) {
builder.addAll(
COMMAND_GET_DEVICE_VOLUME,
COMMAND_SET_DEVICE_VOLUME,
COMMAND_SET_DEVICE_VOLUME_WITH_FLAGS,
COMMAND_ADJUST_DEVICE_VOLUME,
COMMAND_ADJUST_DEVICE_VOLUME_WITH_FLAGS);
}
builder.addAll(additionalCommands);
return builder.build();
}
private static Player.Commands createWithDefaultCommands(
@Player.Command int... additionalCommands) {
return createWithDefaultCommands(/* isTimelineEmpty= */ false, additionalCommands);
return createWithDefaultCommands(
/* isTimelineEmpty= */ false, /* allowDeviceVolumeControl= */ false, additionalCommands);
}
// Internal classes.

View File

@ -54,6 +54,7 @@ public class TestExoPlayerBuilder {
private @MonotonicNonNull Looper looper;
private long seekBackIncrementMs;
private long seekForwardIncrementMs;
private boolean deviceVolumeControlEnabled;
public TestExoPlayerBuilder(Context context) {
this.context = context;
@ -67,6 +68,7 @@ public class TestExoPlayerBuilder {
}
seekBackIncrementMs = C.DEFAULT_SEEK_BACK_INCREMENT_MS;
seekForwardIncrementMs = C.DEFAULT_SEEK_FORWARD_INCREMENT_MS;
deviceVolumeControlEnabled = false;
}
/**
@ -282,6 +284,18 @@ public class TestExoPlayerBuilder {
return this;
}
/**
* Sets the variable controlling player's ability to get/set device volume.
*
* @param deviceVolumeControlEnabled Whether the player can get/set device volume.
* @return This builder.
*/
@CanIgnoreReturnValue
public TestExoPlayerBuilder setDeviceVolumeControlEnabled(boolean deviceVolumeControlEnabled) {
this.deviceVolumeControlEnabled = deviceVolumeControlEnabled;
return this;
}
/** Returns the seek forward increment used by the player. */
public long getSeekForwardIncrementMs() {
return seekForwardIncrementMs;
@ -322,7 +336,8 @@ public class TestExoPlayerBuilder {
.setUseLazyPreparation(useLazyPreparation)
.setLooper(looper)
.setSeekBackIncrementMs(seekBackIncrementMs)
.setSeekForwardIncrementMs(seekForwardIncrementMs);
.setSeekForwardIncrementMs(seekForwardIncrementMs)
.setDeviceVolumeControlEnabled(deviceVolumeControlEnabled);
if (mediaSourceFactory != null) {
builder.setMediaSourceFactory(mediaSourceFactory);
}