mirror of
https://github.com/samsonjs/media.git
synced 2026-04-02 10:45:51 +00:00
Merge AudioFocusManager methods to simplify control flow.
handlePrepare/Stop/SetPlayReady can be merged together as they all handle changes to the desires state of the player. Also, simplify parts of the control flow by not mixing code that determines if audio focus needs to be handled with code that actually acquires or abandons the focus. PiperOrigin-RevId: 299824857
This commit is contained in:
parent
07cbfb65e5
commit
3c0e617837
3 changed files with 172 additions and 251 deletions
|
|
@ -24,7 +24,6 @@ import androidx.annotation.Nullable;
|
|||
import androidx.annotation.RequiresApi;
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
import com.google.android.exoplayer2.audio.AudioAttributes;
|
||||
import com.google.android.exoplayer2.source.MediaSource;
|
||||
import com.google.android.exoplayer2.util.Assertions;
|
||||
import com.google.android.exoplayer2.util.Log;
|
||||
import com.google.android.exoplayer2.util.Util;
|
||||
|
|
@ -134,64 +133,38 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
|||
/**
|
||||
* Sets audio attributes that should be used to manage audio focus.
|
||||
*
|
||||
* <p>Call {@link #updateAudioFocus(boolean, int)} to update the audio focus based on these
|
||||
* attributes.
|
||||
*
|
||||
* @param audioAttributes The audio attributes or {@code null} if audio focus should not be
|
||||
* managed automatically.
|
||||
* @param playWhenReady The current state of {@link ExoPlayer#getPlayWhenReady()}.
|
||||
* @param playerState The current player state; {@link ExoPlayer#getPlaybackState()}.
|
||||
* @return A {@link PlayerCommand} to execute on the player.
|
||||
*/
|
||||
@PlayerCommand
|
||||
public int setAudioAttributes(
|
||||
@Nullable AudioAttributes audioAttributes, boolean playWhenReady, int playerState) {
|
||||
public void setAudioAttributes(@Nullable AudioAttributes audioAttributes) {
|
||||
if (!Util.areEqual(this.audioAttributes, audioAttributes)) {
|
||||
this.audioAttributes = audioAttributes;
|
||||
focusGain = convertAudioAttributesToFocusGain(audioAttributes);
|
||||
|
||||
Assertions.checkArgument(
|
||||
focusGain == C.AUDIOFOCUS_GAIN || focusGain == C.AUDIOFOCUS_NONE,
|
||||
"Automatic handling of audio focus is only available for USAGE_MEDIA and USAGE_GAME.");
|
||||
if (playWhenReady
|
||||
&& (playerState == Player.STATE_BUFFERING || playerState == Player.STATE_READY)) {
|
||||
return requestAudioFocus();
|
||||
}
|
||||
}
|
||||
|
||||
return playerState == Player.STATE_IDLE
|
||||
? handleIdle(playWhenReady)
|
||||
: handlePrepare(playWhenReady);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by a player as part of {@link ExoPlayer#prepare(MediaSource, boolean, boolean)}.
|
||||
*
|
||||
* @param playWhenReady The current state of {@link ExoPlayer#getPlayWhenReady()}.
|
||||
* @return A {@link PlayerCommand} to execute on the player.
|
||||
*/
|
||||
@PlayerCommand
|
||||
public int handlePrepare(boolean playWhenReady) {
|
||||
return playWhenReady ? requestAudioFocus() : PLAYER_COMMAND_DO_NOT_PLAY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by the player as part of {@link ExoPlayer#setPlayWhenReady(boolean)}.
|
||||
* Called by the player to abandon or request audio focus based on the desired player state.
|
||||
*
|
||||
* @param playWhenReady The desired value of playWhenReady.
|
||||
* @param playerState The current state of the player.
|
||||
* @param playbackState The desired playback state.
|
||||
* @return A {@link PlayerCommand} to execute on the player.
|
||||
*/
|
||||
@PlayerCommand
|
||||
public int handleSetPlayWhenReady(boolean playWhenReady, int playerState) {
|
||||
if (!playWhenReady) {
|
||||
abandonAudioFocus();
|
||||
return PLAYER_COMMAND_DO_NOT_PLAY;
|
||||
public int updateAudioFocus(boolean playWhenReady, @Player.State int playbackState) {
|
||||
if (!shouldHandleAudioFocus(playbackState)) {
|
||||
if (audioFocusState != AUDIO_FOCUS_STATE_NO_FOCUS) {
|
||||
abandonAudioFocus();
|
||||
}
|
||||
return playWhenReady ? PLAYER_COMMAND_PLAY_WHEN_READY : PLAYER_COMMAND_DO_NOT_PLAY;
|
||||
}
|
||||
|
||||
return playerState == Player.STATE_IDLE ? handleIdle(playWhenReady) : requestAudioFocus();
|
||||
}
|
||||
|
||||
/** Called by the player as part of {@link ExoPlayer#stop(boolean)}. */
|
||||
public void handleStop() {
|
||||
abandonAudioFocus(/* forceAbandon= */ true);
|
||||
return playWhenReady ? requestAudioFocus() : PLAYER_COMMAND_DO_NOT_PLAY;
|
||||
}
|
||||
|
||||
// Internal methods.
|
||||
|
|
@ -201,22 +174,14 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
|||
return focusListener;
|
||||
}
|
||||
|
||||
@PlayerCommand
|
||||
private int handleIdle(boolean playWhenReady) {
|
||||
return playWhenReady ? PLAYER_COMMAND_PLAY_WHEN_READY : PLAYER_COMMAND_DO_NOT_PLAY;
|
||||
private boolean shouldHandleAudioFocus(@Player.State int playbackState) {
|
||||
return playbackState != Player.STATE_IDLE && focusGain == C.AUDIOFOCUS_GAIN;
|
||||
}
|
||||
|
||||
@PlayerCommand
|
||||
private int requestAudioFocus() {
|
||||
int focusRequestResult;
|
||||
|
||||
if (focusGain == C.AUDIOFOCUS_NONE) {
|
||||
if (audioFocusState != AUDIO_FOCUS_STATE_NO_FOCUS) {
|
||||
abandonAudioFocus(/* forceAbandon= */ true);
|
||||
}
|
||||
return PLAYER_COMMAND_PLAY_WHEN_READY;
|
||||
}
|
||||
|
||||
if (audioFocusState == AUDIO_FOCUS_STATE_NO_FOCUS) {
|
||||
if (Util.SDK_INT >= 26) {
|
||||
focusRequestResult = requestAudioFocusV26();
|
||||
|
|
@ -239,24 +204,15 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
|||
}
|
||||
|
||||
private void abandonAudioFocus() {
|
||||
abandonAudioFocus(/* forceAbandon= */ false);
|
||||
}
|
||||
|
||||
private void abandonAudioFocus(boolean forceAbandon) {
|
||||
if (focusGain == C.AUDIOFOCUS_NONE && audioFocusState == AUDIO_FOCUS_STATE_NO_FOCUS) {
|
||||
if (audioFocusState == AUDIO_FOCUS_STATE_NO_FOCUS) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (focusGain != C.AUDIOFOCUS_GAIN
|
||||
|| audioFocusState == AUDIO_FOCUS_STATE_LOST_FOCUS
|
||||
|| forceAbandon) {
|
||||
if (Util.SDK_INT >= 26) {
|
||||
abandonAudioFocusV26();
|
||||
} else {
|
||||
abandonAudioFocusDefault();
|
||||
}
|
||||
audioFocusState = AUDIO_FOCUS_STATE_NO_FOCUS;
|
||||
if (Util.SDK_INT >= 26) {
|
||||
abandonAudioFocusV26();
|
||||
} else {
|
||||
abandonAudioFocusDefault();
|
||||
}
|
||||
audioFocusState = AUDIO_FOCUS_STATE_NO_FOCUS;
|
||||
}
|
||||
|
||||
private int requestAudioFocusDefault() {
|
||||
|
|
@ -312,7 +268,6 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
|||
*/
|
||||
@C.AudioFocusGain
|
||||
private static int convertAudioAttributesToFocusGain(@Nullable AudioAttributes audioAttributes) {
|
||||
|
||||
if (audioAttributes == null) {
|
||||
// Don't handle audio focus. It may be either video only contents or developers
|
||||
// want to have more finer grained control. (e.g. adding audio focus listener)
|
||||
|
|
@ -414,7 +369,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
|||
break;
|
||||
case AUDIO_FOCUS_STATE_LOST_FOCUS:
|
||||
playerControl.executePlayerCommand(PLAYER_COMMAND_DO_NOT_PLAY);
|
||||
abandonAudioFocus(/* forceAbandon= */ true);
|
||||
abandonAudioFocus();
|
||||
break;
|
||||
case AUDIO_FOCUS_STATE_LOSS_TRANSIENT:
|
||||
playerControl.executePlayerCommand(PLAYER_COMMAND_WAIT_FOR_CALLBACK);
|
||||
|
|
|
|||
|
|
@ -686,10 +686,10 @@ public class SimpleExoPlayer extends BasePlayer
|
|||
}
|
||||
}
|
||||
|
||||
audioFocusManager.setAudioAttributes(handleAudioFocus ? audioAttributes : null);
|
||||
boolean playWhenReady = getPlayWhenReady();
|
||||
@AudioFocusManager.PlayerCommand
|
||||
int playerCommand =
|
||||
audioFocusManager.setAudioAttributes(
|
||||
handleAudioFocus ? audioAttributes : null, getPlayWhenReady(), getPlaybackState());
|
||||
int playerCommand = audioFocusManager.updateAudioFocus(playWhenReady, getPlaybackState());
|
||||
updatePlayWhenReady(getPlayWhenReady(), playerCommand);
|
||||
}
|
||||
|
||||
|
|
@ -1190,7 +1190,7 @@ public class SimpleExoPlayer extends BasePlayer
|
|||
this.mediaSource = mediaSource;
|
||||
mediaSource.addEventListener(eventHandler, analyticsCollector);
|
||||
@AudioFocusManager.PlayerCommand
|
||||
int playerCommand = audioFocusManager.handlePrepare(getPlayWhenReady());
|
||||
int playerCommand = audioFocusManager.updateAudioFocus(getPlayWhenReady(), Player.STATE_BUFFERING);
|
||||
updatePlayWhenReady(getPlayWhenReady(), playerCommand);
|
||||
player.prepare(mediaSource, resetPosition, resetState);
|
||||
}
|
||||
|
|
@ -1199,7 +1199,7 @@ public class SimpleExoPlayer extends BasePlayer
|
|||
public void setPlayWhenReady(boolean playWhenReady) {
|
||||
verifyApplicationThread();
|
||||
@AudioFocusManager.PlayerCommand
|
||||
int playerCommand = audioFocusManager.handleSetPlayWhenReady(playWhenReady, getPlaybackState());
|
||||
int playerCommand = audioFocusManager.updateAudioFocus(playWhenReady, getPlaybackState());
|
||||
updatePlayWhenReady(playWhenReady, playerCommand);
|
||||
}
|
||||
|
||||
|
|
@ -1278,6 +1278,7 @@ public class SimpleExoPlayer extends BasePlayer
|
|||
@Override
|
||||
public void stop(boolean reset) {
|
||||
verifyApplicationThread();
|
||||
audioFocusManager.updateAudioFocus(getPlayWhenReady(), Player.STATE_IDLE);
|
||||
player.stop(reset);
|
||||
if (mediaSource != null) {
|
||||
mediaSource.removeEventListener(analyticsCollector);
|
||||
|
|
@ -1286,7 +1287,6 @@ public class SimpleExoPlayer extends BasePlayer
|
|||
mediaSource = null;
|
||||
}
|
||||
}
|
||||
audioFocusManager.handleStop();
|
||||
currentCues = Collections.emptyList();
|
||||
}
|
||||
|
||||
|
|
@ -1294,7 +1294,7 @@ public class SimpleExoPlayer extends BasePlayer
|
|||
public void release() {
|
||||
verifyApplicationThread();
|
||||
audioBecomingNoisyManager.setEnabled(false);
|
||||
audioFocusManager.handleStop();
|
||||
audioFocusManager.updateAudioFocus(/* playWhenReady= */ false, Player.STATE_IDLE);
|
||||
wakeLockManager.setStayAwake(false);
|
||||
wifiLockManager.setStayAwake(false);
|
||||
player.release();
|
||||
|
|
|
|||
|
|
@ -65,13 +65,11 @@ public class AudioFocusManagerTest {
|
|||
@Test
|
||||
public void setAudioAttributes_withNullUsage_doesNotManageAudioFocus() {
|
||||
// Ensure that NULL audio attributes -> don't manage audio focus
|
||||
assertThat(
|
||||
audioFocusManager.setAudioAttributes(
|
||||
/* audioAttributes= */ null, /* playWhenReady= */ false, Player.STATE_IDLE))
|
||||
audioFocusManager.setAudioAttributes(/* audioAttributes= */ null);
|
||||
|
||||
assertThat(audioFocusManager.updateAudioFocus(/* playWhenReady= */ false, Player.STATE_IDLE))
|
||||
.isEqualTo(PLAYER_COMMAND_DO_NOT_PLAY);
|
||||
assertThat(
|
||||
audioFocusManager.setAudioAttributes(
|
||||
/* audioAttributes= */ null, /* playWhenReady= */ true, Player.STATE_READY))
|
||||
assertThat(audioFocusManager.updateAudioFocus(/* playWhenReady= */ true, Player.STATE_READY))
|
||||
.isEqualTo(PLAYER_COMMAND_PLAY_WHEN_READY);
|
||||
ShadowAudioManager.AudioFocusRequest request =
|
||||
Shadows.shadowOf(audioManager).getLastAudioFocusRequest();
|
||||
|
|
@ -85,18 +83,17 @@ public class AudioFocusManagerTest {
|
|||
AudioAttributes media = new AudioAttributes.Builder().setUsage(C.USAGE_MEDIA).build();
|
||||
Shadows.shadowOf(audioManager)
|
||||
.setNextFocusRequestResponse(AudioManager.AUDIOFOCUS_REQUEST_GRANTED);
|
||||
assertThat(
|
||||
audioFocusManager.setAudioAttributes(
|
||||
media, /* playWhenReady= */ true, Player.STATE_READY))
|
||||
audioFocusManager.setAudioAttributes(media);
|
||||
assertThat(audioFocusManager.updateAudioFocus(/* playWhenReady= */ true, Player.STATE_READY))
|
||||
.isEqualTo(PLAYER_COMMAND_PLAY_WHEN_READY);
|
||||
ShadowAudioManager.AudioFocusRequest request =
|
||||
Shadows.shadowOf(audioManager).getLastAudioFocusRequest();
|
||||
assertThat(request.durationHint).isEqualTo(AudioManager.AUDIOFOCUS_GAIN);
|
||||
|
||||
// Ensure that setting null audio attributes with audio focus releases audio focus.
|
||||
assertThat(
|
||||
audioFocusManager.setAudioAttributes(
|
||||
/* audioAttributes= */ null, /* playWhenReady= */ true, Player.STATE_READY))
|
||||
audioFocusManager.setAudioAttributes(/* audioAttributes= */ null);
|
||||
|
||||
assertThat(audioFocusManager.updateAudioFocus(/* playWhenReady= */ true, Player.STATE_READY))
|
||||
.isEqualTo(PLAYER_COMMAND_PLAY_WHEN_READY);
|
||||
AudioManager.OnAudioFocusChangeListener lastRequest =
|
||||
Shadows.shadowOf(audioManager).getLastAbandonedAudioFocusListener();
|
||||
|
|
@ -110,18 +107,16 @@ public class AudioFocusManagerTest {
|
|||
AudioAttributes media = new AudioAttributes.Builder().setUsage(C.USAGE_MEDIA).build();
|
||||
Shadows.shadowOf(audioManager)
|
||||
.setNextFocusRequestResponse(AudioManager.AUDIOFOCUS_REQUEST_GRANTED);
|
||||
assertThat(
|
||||
audioFocusManager.setAudioAttributes(
|
||||
media, /* playWhenReady= */ true, Player.STATE_READY))
|
||||
audioFocusManager.setAudioAttributes(media);
|
||||
assertThat(audioFocusManager.updateAudioFocus(/* playWhenReady= */ true, Player.STATE_READY))
|
||||
.isEqualTo(PLAYER_COMMAND_PLAY_WHEN_READY);
|
||||
ShadowAudioManager.AudioFocusRequest request =
|
||||
Shadows.shadowOf(audioManager).getLastAudioFocusRequest();
|
||||
assertThat(getAudioFocusGainFromRequest(request)).isEqualTo(AudioManager.AUDIOFOCUS_GAIN);
|
||||
|
||||
// Ensure that setting null audio attributes with audio focus releases audio focus.
|
||||
assertThat(
|
||||
audioFocusManager.setAudioAttributes(
|
||||
/* audioAttributes= */ null, /* playWhenReady= */ true, Player.STATE_READY))
|
||||
audioFocusManager.setAudioAttributes(/* audioAttributes= */ null);
|
||||
assertThat(audioFocusManager.updateAudioFocus(/* playWhenReady= */ true, Player.STATE_READY))
|
||||
.isEqualTo(PLAYER_COMMAND_PLAY_WHEN_READY);
|
||||
AudioFocusRequest lastRequest =
|
||||
Shadows.shadowOf(audioManager).getLastAbandonedAudioFocusRequest();
|
||||
|
|
@ -130,10 +125,10 @@ public class AudioFocusManagerTest {
|
|||
|
||||
@Test
|
||||
public void setAudioAttributes_withUsageAlarm_throwsIllegalArgumentException() {
|
||||
// Ensure that audio attributes that map to AUDIOFOCUS_GAIN_TRANSIENT* throw
|
||||
// Ensure that audio attributes that map to AUDIOFOCUS_GAIN_TRANSIENT* throw.
|
||||
AudioAttributes alarm = new AudioAttributes.Builder().setUsage(C.USAGE_ALARM).build();
|
||||
try {
|
||||
audioFocusManager.setAudioAttributes(alarm, /* playWhenReady= */ false, Player.STATE_IDLE);
|
||||
audioFocusManager.setAudioAttributes(alarm);
|
||||
fail();
|
||||
} catch (IllegalArgumentException e) {
|
||||
// Expected
|
||||
|
|
@ -147,9 +142,9 @@ public class AudioFocusManagerTest {
|
|||
Shadows.shadowOf(audioManager)
|
||||
.setNextFocusRequestResponse(AudioManager.AUDIOFOCUS_REQUEST_GRANTED);
|
||||
|
||||
assertThat(
|
||||
audioFocusManager.setAudioAttributes(
|
||||
media, /* playWhenReady= */ true, Player.STATE_READY))
|
||||
audioFocusManager.setAudioAttributes(media);
|
||||
|
||||
assertThat(audioFocusManager.updateAudioFocus(/* playWhenReady= */ true, Player.STATE_READY))
|
||||
.isEqualTo(PLAYER_COMMAND_PLAY_WHEN_READY);
|
||||
ShadowAudioManager.AudioFocusRequest request =
|
||||
Shadows.shadowOf(audioManager).getLastAudioFocusRequest();
|
||||
|
|
@ -163,9 +158,9 @@ public class AudioFocusManagerTest {
|
|||
Shadows.shadowOf(audioManager)
|
||||
.setNextFocusRequestResponse(AudioManager.AUDIOFOCUS_REQUEST_GRANTED);
|
||||
|
||||
assertThat(
|
||||
audioFocusManager.setAudioAttributes(
|
||||
media, /* playWhenReady= */ true, Player.STATE_ENDED))
|
||||
audioFocusManager.setAudioAttributes(media);
|
||||
|
||||
assertThat(audioFocusManager.updateAudioFocus(/* playWhenReady= */ true, Player.STATE_ENDED))
|
||||
.isEqualTo(PLAYER_COMMAND_PLAY_WHEN_READY);
|
||||
ShadowAudioManager.AudioFocusRequest request =
|
||||
Shadows.shadowOf(audioManager).getLastAudioFocusRequest();
|
||||
|
|
@ -173,42 +168,131 @@ public class AudioFocusManagerTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void handlePrepare_afterSetAudioAttributes_setsPlayerCommandPlayWhenReady() {
|
||||
public void updateAudioFocusFromIdleToBuffering_setsPlayerCommandPlayWhenReady() {
|
||||
// Ensure that when playWhenReady is true while the player is IDLE, audio focus is only
|
||||
// requested after calling handlePrepare.
|
||||
// requested after calling prepare (= changing the state to BUFFERING).
|
||||
AudioAttributes media = new AudioAttributes.Builder().setUsage(C.USAGE_MEDIA).build();
|
||||
|
||||
Shadows.shadowOf(audioManager)
|
||||
.setNextFocusRequestResponse(AudioManager.AUDIOFOCUS_REQUEST_GRANTED);
|
||||
audioFocusManager.setAudioAttributes(media);
|
||||
|
||||
assertThat(
|
||||
audioFocusManager.setAudioAttributes(
|
||||
media, /* playWhenReady= */ true, Player.STATE_IDLE))
|
||||
assertThat(audioFocusManager.updateAudioFocus(/* playWhenReady= */ true, Player.STATE_IDLE))
|
||||
.isEqualTo(PLAYER_COMMAND_PLAY_WHEN_READY);
|
||||
assertThat(Shadows.shadowOf(audioManager).getLastAudioFocusRequest()).isNull();
|
||||
assertThat(audioFocusManager.handlePrepare(/* playWhenReady= */ true))
|
||||
assertThat(
|
||||
audioFocusManager.updateAudioFocus(/* playWhenReady= */ true, Player.STATE_BUFFERING))
|
||||
.isEqualTo(PLAYER_COMMAND_PLAY_WHEN_READY);
|
||||
ShadowAudioManager.AudioFocusRequest request =
|
||||
Shadows.shadowOf(audioManager).getLastAudioFocusRequest();
|
||||
assertThat(getAudioFocusGainFromRequest(request)).isEqualTo(AudioManager.AUDIOFOCUS_GAIN);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void handleSetPlayWhenReady_afterSetAudioAttributes_setsPlayerCommandPlayWhenReady() {
|
||||
public void updateAudioFocusFromPausedToPlaying_setsPlayerCommandPlayWhenReady() {
|
||||
// Ensure that audio focus is not requested until playWhenReady is true.
|
||||
AudioAttributes media = new AudioAttributes.Builder().setUsage(C.USAGE_MEDIA).build();
|
||||
|
||||
Shadows.shadowOf(audioManager)
|
||||
.setNextFocusRequestResponse(AudioManager.AUDIOFOCUS_REQUEST_GRANTED);
|
||||
audioFocusManager.setAudioAttributes(media);
|
||||
|
||||
assertThat(audioFocusManager.handlePrepare(/* playWhenReady= */ false))
|
||||
assertThat(audioFocusManager.updateAudioFocus(/* playWhenReady= */ false, Player.STATE_READY))
|
||||
.isEqualTo(PLAYER_COMMAND_DO_NOT_PLAY);
|
||||
assertThat(Shadows.shadowOf(audioManager).getLastAudioFocusRequest()).isNull();
|
||||
assertThat(
|
||||
audioFocusManager.setAudioAttributes(
|
||||
media, /* playWhenReady= */ false, Player.STATE_READY))
|
||||
.isEqualTo(PLAYER_COMMAND_DO_NOT_PLAY);
|
||||
assertThat(Shadows.shadowOf(audioManager).getLastAudioFocusRequest()).isNull();
|
||||
assertThat(
|
||||
audioFocusManager.handleSetPlayWhenReady(/* playWhenReady= */ true, Player.STATE_READY))
|
||||
|
||||
assertThat(audioFocusManager.updateAudioFocus(/* playWhenReady= */ true, Player.STATE_READY))
|
||||
.isEqualTo(PLAYER_COMMAND_PLAY_WHEN_READY);
|
||||
ShadowAudioManager.AudioFocusRequest request =
|
||||
Shadows.shadowOf(audioManager).getLastAudioFocusRequest();
|
||||
assertThat(getAudioFocusGainFromRequest(request)).isEqualTo(AudioManager.AUDIOFOCUS_GAIN);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Config(maxSdk = 25)
|
||||
public void updateAudioFocusFromReadyToIdle_abandonsAudioFocus() {
|
||||
// Ensure that stopping the player (=changing state to idle) abandons audio focus.
|
||||
AudioAttributes media =
|
||||
new AudioAttributes.Builder()
|
||||
.setUsage(C.USAGE_MEDIA)
|
||||
.setContentType(C.CONTENT_TYPE_SPEECH)
|
||||
.build();
|
||||
Shadows.shadowOf(audioManager)
|
||||
.setNextFocusRequestResponse(AudioManager.AUDIOFOCUS_REQUEST_GRANTED);
|
||||
audioFocusManager.setAudioAttributes(media);
|
||||
assertThat(audioFocusManager.updateAudioFocus(/* playWhenReady= */ true, Player.STATE_READY))
|
||||
.isEqualTo(PLAYER_COMMAND_PLAY_WHEN_READY);
|
||||
assertThat(Shadows.shadowOf(audioManager).getLastAbandonedAudioFocusListener()).isNull();
|
||||
|
||||
ShadowAudioManager.AudioFocusRequest request =
|
||||
Shadows.shadowOf(audioManager).getLastAudioFocusRequest();
|
||||
assertThat(audioFocusManager.updateAudioFocus(/* playWhenReady= */ true, Player.STATE_IDLE))
|
||||
.isEqualTo(PLAYER_COMMAND_PLAY_WHEN_READY);
|
||||
assertThat(Shadows.shadowOf(audioManager).getLastAbandonedAudioFocusListener())
|
||||
.isEqualTo(request.listener);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Config(minSdk = 26, maxSdk = TARGET_SDK)
|
||||
public void updateAudioFocusFromReadyToIdle_abandonsAudioFocus_v26() {
|
||||
// Ensure that stopping the player (=changing state to idle) abandons audio focus.
|
||||
AudioAttributes media =
|
||||
new AudioAttributes.Builder()
|
||||
.setUsage(C.USAGE_MEDIA)
|
||||
.setContentType(C.CONTENT_TYPE_SPEECH)
|
||||
.build();
|
||||
Shadows.shadowOf(audioManager)
|
||||
.setNextFocusRequestResponse(AudioManager.AUDIOFOCUS_REQUEST_GRANTED);
|
||||
audioFocusManager.setAudioAttributes(media);
|
||||
|
||||
assertThat(audioFocusManager.updateAudioFocus(/* playWhenReady= */ true, Player.STATE_READY))
|
||||
.isEqualTo(PLAYER_COMMAND_PLAY_WHEN_READY);
|
||||
assertThat(Shadows.shadowOf(audioManager).getLastAbandonedAudioFocusRequest()).isNull();
|
||||
|
||||
ShadowAudioManager.AudioFocusRequest request =
|
||||
Shadows.shadowOf(audioManager).getLastAudioFocusRequest();
|
||||
assertThat(audioFocusManager.updateAudioFocus(/* playWhenReady= */ true, Player.STATE_IDLE))
|
||||
.isEqualTo(PLAYER_COMMAND_PLAY_WHEN_READY);
|
||||
assertThat(Shadows.shadowOf(audioManager).getLastAbandonedAudioFocusRequest())
|
||||
.isEqualTo(request.audioFocusRequest);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Config(maxSdk = 25)
|
||||
public void updateAudioFocusFromReadyToIdle_withoutHandlingAudioFocus_isNoOp() {
|
||||
// Ensure that changing state to idle is a no-op if audio focus isn't handled.
|
||||
Shadows.shadowOf(audioManager)
|
||||
.setNextFocusRequestResponse(AudioManager.AUDIOFOCUS_REQUEST_GRANTED);
|
||||
audioFocusManager.setAudioAttributes(null);
|
||||
|
||||
assertThat(audioFocusManager.updateAudioFocus(/* playWhenReady= */ false, Player.STATE_READY))
|
||||
.isEqualTo(PLAYER_COMMAND_DO_NOT_PLAY);
|
||||
assertThat(Shadows.shadowOf(audioManager).getLastAbandonedAudioFocusListener()).isNull();
|
||||
ShadowAudioManager.AudioFocusRequest request =
|
||||
Shadows.shadowOf(audioManager).getLastAudioFocusRequest();
|
||||
assertThat(request).isNull();
|
||||
|
||||
assertThat(audioFocusManager.updateAudioFocus(/* playWhenReady= */ false, Player.STATE_IDLE))
|
||||
.isEqualTo(PLAYER_COMMAND_DO_NOT_PLAY);
|
||||
assertThat(Shadows.shadowOf(audioManager).getLastAbandonedAudioFocusListener()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Config(minSdk = 26, maxSdk = TARGET_SDK)
|
||||
public void updateAudioFocusFromReadyToIdle_withoutHandlingAudioFocus_isNoOp_v26() {
|
||||
// Ensure that changing state to idle is a no-op if audio focus isn't handled.
|
||||
Shadows.shadowOf(audioManager)
|
||||
.setNextFocusRequestResponse(AudioManager.AUDIOFOCUS_REQUEST_GRANTED);
|
||||
audioFocusManager.setAudioAttributes(null);
|
||||
|
||||
assertThat(audioFocusManager.updateAudioFocus(/* playWhenReady= */ false, Player.STATE_READY))
|
||||
.isEqualTo(PLAYER_COMMAND_DO_NOT_PLAY);
|
||||
assertThat(Shadows.shadowOf(audioManager).getLastAbandonedAudioFocusRequest()).isNull();
|
||||
ShadowAudioManager.AudioFocusRequest request =
|
||||
Shadows.shadowOf(audioManager).getLastAudioFocusRequest();
|
||||
assertThat(request).isNull();
|
||||
|
||||
assertThat(audioFocusManager.updateAudioFocus(/* playWhenReady= */ false, Player.STATE_IDLE))
|
||||
.isEqualTo(PLAYER_COMMAND_DO_NOT_PLAY);
|
||||
assertThat(Shadows.shadowOf(audioManager).getLastAbandonedAudioFocusRequest()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -217,17 +301,17 @@ public class AudioFocusManagerTest {
|
|||
// AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK, and returns to the default value after focus is
|
||||
// regained.
|
||||
AudioAttributes media = new AudioAttributes.Builder().setUsage(C.USAGE_MEDIA).build();
|
||||
|
||||
Shadows.shadowOf(audioManager)
|
||||
.setNextFocusRequestResponse(AudioManager.AUDIOFOCUS_REQUEST_GRANTED);
|
||||
assertThat(
|
||||
audioFocusManager.setAudioAttributes(
|
||||
media, /* playWhenReady= */ true, Player.STATE_READY))
|
||||
audioFocusManager.setAudioAttributes(media);
|
||||
|
||||
assertThat(audioFocusManager.updateAudioFocus(/* playWhenReady= */ true, Player.STATE_READY))
|
||||
.isEqualTo(PLAYER_COMMAND_PLAY_WHEN_READY);
|
||||
|
||||
audioFocusManager
|
||||
.getFocusListener()
|
||||
.onAudioFocusChange(AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK);
|
||||
|
||||
assertThat(testPlayerControl.lastVolumeMultiplier).isLessThan(1.0f);
|
||||
assertThat(testPlayerControl.lastPlayerCommand).isEqualTo(NO_COMMAND_RECEIVED);
|
||||
audioFocusManager.getFocusListener().onAudioFocusChange(AudioManager.AUDIOFOCUS_GAIN);
|
||||
|
|
@ -243,12 +327,11 @@ public class AudioFocusManagerTest {
|
|||
.setUsage(C.USAGE_MEDIA)
|
||||
.setContentType(C.CONTENT_TYPE_SPEECH)
|
||||
.build();
|
||||
|
||||
Shadows.shadowOf(audioManager)
|
||||
.setNextFocusRequestResponse(AudioManager.AUDIOFOCUS_REQUEST_GRANTED);
|
||||
assertThat(
|
||||
audioFocusManager.setAudioAttributes(
|
||||
media, /* playWhenReady= */ true, Player.STATE_READY))
|
||||
audioFocusManager.setAudioAttributes(media);
|
||||
|
||||
assertThat(audioFocusManager.updateAudioFocus(/* playWhenReady= */ true, Player.STATE_READY))
|
||||
.isEqualTo(PLAYER_COMMAND_PLAY_WHEN_READY);
|
||||
|
||||
audioFocusManager
|
||||
|
|
@ -265,12 +348,11 @@ public class AudioFocusManagerTest {
|
|||
// Ensure that the player is commanded to pause when audio focus is lost with
|
||||
// AUDIOFOCUS_LOSS_TRANSIENT.
|
||||
AudioAttributes media = new AudioAttributes.Builder().setUsage(C.USAGE_MEDIA).build();
|
||||
|
||||
Shadows.shadowOf(audioManager)
|
||||
.setNextFocusRequestResponse(AudioManager.AUDIOFOCUS_REQUEST_GRANTED);
|
||||
assertThat(
|
||||
audioFocusManager.setAudioAttributes(
|
||||
media, /* playWhenReady= */ true, Player.STATE_READY))
|
||||
audioFocusManager.setAudioAttributes(media);
|
||||
|
||||
assertThat(audioFocusManager.updateAudioFocus(/* playWhenReady= */ true, Player.STATE_READY))
|
||||
.isEqualTo(PLAYER_COMMAND_PLAY_WHEN_READY);
|
||||
|
||||
audioFocusManager.getFocusListener().onAudioFocusChange(AudioManager.AUDIOFOCUS_LOSS_TRANSIENT);
|
||||
|
|
@ -288,12 +370,11 @@ public class AudioFocusManagerTest {
|
|||
.setUsage(C.USAGE_MEDIA)
|
||||
.setContentType(C.CONTENT_TYPE_SPEECH)
|
||||
.build();
|
||||
|
||||
Shadows.shadowOf(audioManager)
|
||||
.setNextFocusRequestResponse(AudioManager.AUDIOFOCUS_REQUEST_GRANTED);
|
||||
assertThat(
|
||||
audioFocusManager.setAudioAttributes(
|
||||
media, /* playWhenReady= */ true, Player.STATE_READY))
|
||||
audioFocusManager.setAudioAttributes(media);
|
||||
|
||||
assertThat(audioFocusManager.updateAudioFocus(/* playWhenReady= */ true, Player.STATE_READY))
|
||||
.isEqualTo(PLAYER_COMMAND_PLAY_WHEN_READY);
|
||||
assertThat(Shadows.shadowOf(audioManager).getLastAbandonedAudioFocusListener()).isNull();
|
||||
|
||||
|
|
@ -315,12 +396,11 @@ public class AudioFocusManagerTest {
|
|||
.setUsage(C.USAGE_MEDIA)
|
||||
.setContentType(C.CONTENT_TYPE_SPEECH)
|
||||
.build();
|
||||
|
||||
Shadows.shadowOf(audioManager)
|
||||
.setNextFocusRequestResponse(AudioManager.AUDIOFOCUS_REQUEST_GRANTED);
|
||||
assertThat(
|
||||
audioFocusManager.setAudioAttributes(
|
||||
media, /* playWhenReady= */ true, Player.STATE_READY))
|
||||
audioFocusManager.setAudioAttributes(media);
|
||||
|
||||
assertThat(audioFocusManager.updateAudioFocus(/* playWhenReady= */ true, Player.STATE_READY))
|
||||
.isEqualTo(PLAYER_COMMAND_PLAY_WHEN_READY);
|
||||
assertThat(Shadows.shadowOf(audioManager).getLastAbandonedAudioFocusRequest()).isNull();
|
||||
|
||||
|
|
@ -330,120 +410,6 @@ public class AudioFocusManagerTest {
|
|||
.isEqualTo(Shadows.shadowOf(audioManager).getLastAudioFocusRequest().audioFocusRequest);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Config(maxSdk = 25)
|
||||
public void handleStop_withAudioFocus_abandonsAudioFocus() {
|
||||
// Ensure that handleStop causes AudioFocusManager to abandon audio focus.
|
||||
AudioAttributes media =
|
||||
new AudioAttributes.Builder()
|
||||
.setUsage(C.USAGE_MEDIA)
|
||||
.setContentType(C.CONTENT_TYPE_SPEECH)
|
||||
.build();
|
||||
|
||||
Shadows.shadowOf(audioManager)
|
||||
.setNextFocusRequestResponse(AudioManager.AUDIOFOCUS_REQUEST_GRANTED);
|
||||
assertThat(
|
||||
audioFocusManager.setAudioAttributes(
|
||||
media, /* playWhenReady= */ true, Player.STATE_READY))
|
||||
.isEqualTo(PLAYER_COMMAND_PLAY_WHEN_READY);
|
||||
assertThat(Shadows.shadowOf(audioManager).getLastAbandonedAudioFocusListener()).isNull();
|
||||
|
||||
ShadowAudioManager.AudioFocusRequest request =
|
||||
Shadows.shadowOf(audioManager).getLastAudioFocusRequest();
|
||||
audioFocusManager.handleStop();
|
||||
assertThat(Shadows.shadowOf(audioManager).getLastAbandonedAudioFocusListener())
|
||||
.isEqualTo(request.listener);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Config(minSdk = 26, maxSdk = TARGET_SDK)
|
||||
public void handleStop_withAudioFocus_abandonsAudioFocus_v26() {
|
||||
// Ensure that handleStop causes AudioFocusManager to abandon audio focus.
|
||||
AudioAttributes media =
|
||||
new AudioAttributes.Builder()
|
||||
.setUsage(C.USAGE_MEDIA)
|
||||
.setContentType(C.CONTENT_TYPE_SPEECH)
|
||||
.build();
|
||||
|
||||
Shadows.shadowOf(audioManager)
|
||||
.setNextFocusRequestResponse(AudioManager.AUDIOFOCUS_REQUEST_GRANTED);
|
||||
assertThat(
|
||||
audioFocusManager.setAudioAttributes(
|
||||
media, /* playWhenReady= */ true, Player.STATE_READY))
|
||||
.isEqualTo(PLAYER_COMMAND_PLAY_WHEN_READY);
|
||||
assertThat(Shadows.shadowOf(audioManager).getLastAbandonedAudioFocusRequest()).isNull();
|
||||
|
||||
ShadowAudioManager.AudioFocusRequest request =
|
||||
Shadows.shadowOf(audioManager).getLastAudioFocusRequest();
|
||||
audioFocusManager.handleStop();
|
||||
assertThat(Shadows.shadowOf(audioManager).getLastAbandonedAudioFocusRequest())
|
||||
.isEqualTo(request.audioFocusRequest);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Config(maxSdk = 25)
|
||||
public void handleStop_withoutAudioFocus_stillAbandonsFocus() {
|
||||
// Ensure that handleStop causes AudioFocusManager to call through to abandon audio focus
|
||||
// even if focus wasn't requested.
|
||||
AudioAttributes media =
|
||||
new AudioAttributes.Builder()
|
||||
.setUsage(C.USAGE_MEDIA)
|
||||
.setContentType(C.CONTENT_TYPE_SPEECH)
|
||||
.build();
|
||||
|
||||
Shadows.shadowOf(audioManager)
|
||||
.setNextFocusRequestResponse(AudioManager.AUDIOFOCUS_REQUEST_GRANTED);
|
||||
assertThat(
|
||||
audioFocusManager.setAudioAttributes(
|
||||
media, /* playWhenReady= */ false, Player.STATE_READY))
|
||||
.isEqualTo(PLAYER_COMMAND_DO_NOT_PLAY);
|
||||
assertThat(Shadows.shadowOf(audioManager).getLastAbandonedAudioFocusListener()).isNull();
|
||||
ShadowAudioManager.AudioFocusRequest request =
|
||||
Shadows.shadowOf(audioManager).getLastAudioFocusRequest();
|
||||
assertThat(request).isNull();
|
||||
|
||||
audioFocusManager.handleStop();
|
||||
assertThat(Shadows.shadowOf(audioManager).getLastAbandonedAudioFocusListener()).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Config(maxSdk = 25)
|
||||
public void handleStop_withoutHandlingAudioFocus_isNoOp() {
|
||||
// Ensure that handleStop is a no-op if audio focus isn't handled.
|
||||
Shadows.shadowOf(audioManager)
|
||||
.setNextFocusRequestResponse(AudioManager.AUDIOFOCUS_REQUEST_GRANTED);
|
||||
assertThat(
|
||||
audioFocusManager.setAudioAttributes(
|
||||
/* audioAttributes= */ null, /* playWhenReady= */ false, Player.STATE_READY))
|
||||
.isEqualTo(PLAYER_COMMAND_DO_NOT_PLAY);
|
||||
assertThat(Shadows.shadowOf(audioManager).getLastAbandonedAudioFocusListener()).isNull();
|
||||
ShadowAudioManager.AudioFocusRequest request =
|
||||
Shadows.shadowOf(audioManager).getLastAudioFocusRequest();
|
||||
assertThat(request).isNull();
|
||||
|
||||
audioFocusManager.handleStop();
|
||||
assertThat(Shadows.shadowOf(audioManager).getLastAbandonedAudioFocusListener()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Config(minSdk = 26, maxSdk = TARGET_SDK)
|
||||
public void handleStop_withoutHandlingAudioFocus_isNoOp_v26() {
|
||||
// Ensure that handleStop is a no-op if audio focus isn't handled.
|
||||
Shadows.shadowOf(audioManager)
|
||||
.setNextFocusRequestResponse(AudioManager.AUDIOFOCUS_REQUEST_GRANTED);
|
||||
assertThat(
|
||||
audioFocusManager.setAudioAttributes(
|
||||
/* audioAttributes= */ null, /* playWhenReady= */ false, Player.STATE_READY))
|
||||
.isEqualTo(PLAYER_COMMAND_DO_NOT_PLAY);
|
||||
assertThat(Shadows.shadowOf(audioManager).getLastAbandonedAudioFocusRequest()).isNull();
|
||||
ShadowAudioManager.AudioFocusRequest request =
|
||||
Shadows.shadowOf(audioManager).getLastAudioFocusRequest();
|
||||
assertThat(request).isNull();
|
||||
|
||||
audioFocusManager.handleStop();
|
||||
assertThat(Shadows.shadowOf(audioManager).getLastAbandonedAudioFocusRequest()).isNull();
|
||||
}
|
||||
|
||||
private int getAudioFocusGainFromRequest(ShadowAudioManager.AudioFocusRequest audioFocusRequest) {
|
||||
return Util.SDK_INT >= 26
|
||||
? audioFocusRequest.audioFocusRequest.getFocusGain()
|
||||
|
|
|
|||
Loading…
Reference in a new issue