mirror of
https://github.com/samsonjs/media.git
synced 2026-04-27 15:07:40 +00:00
Test audio focus denial
- Verifies that playWhenReady doesn't become true if audio focus is denied. - Also verifies there's no suppression reason in this case, because the denial is permanent rather than temporary. PiperOrigin-RevId: 274141099
This commit is contained in:
parent
46c6f260f5
commit
a268e1b63f
1 changed files with 44 additions and 29 deletions
|
|
@ -17,9 +17,11 @@ package com.google.android.exoplayer2;
|
||||||
|
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
import static org.junit.Assert.fail;
|
import static org.junit.Assert.fail;
|
||||||
|
import static org.robolectric.Shadows.shadowOf;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.graphics.SurfaceTexture;
|
import android.graphics.SurfaceTexture;
|
||||||
|
import android.media.AudioManager;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.view.Surface;
|
import android.view.Surface;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
|
@ -29,6 +31,7 @@ import com.google.android.exoplayer2.Player.DiscontinuityReason;
|
||||||
import com.google.android.exoplayer2.Player.EventListener;
|
import com.google.android.exoplayer2.Player.EventListener;
|
||||||
import com.google.android.exoplayer2.Timeline.Window;
|
import com.google.android.exoplayer2.Timeline.Window;
|
||||||
import com.google.android.exoplayer2.analytics.AnalyticsListener;
|
import com.google.android.exoplayer2.analytics.AnalyticsListener;
|
||||||
|
import com.google.android.exoplayer2.audio.AudioAttributes;
|
||||||
import com.google.android.exoplayer2.source.ClippingMediaSource;
|
import com.google.android.exoplayer2.source.ClippingMediaSource;
|
||||||
import com.google.android.exoplayer2.source.ConcatenatingMediaSource;
|
import com.google.android.exoplayer2.source.ConcatenatingMediaSource;
|
||||||
import com.google.android.exoplayer2.source.MediaSource;
|
import com.google.android.exoplayer2.source.MediaSource;
|
||||||
|
|
@ -55,7 +58,6 @@ import com.google.android.exoplayer2.testutil.FakeTrackSelector;
|
||||||
import com.google.android.exoplayer2.trackselection.TrackSelectionArray;
|
import com.google.android.exoplayer2.trackselection.TrackSelectionArray;
|
||||||
import com.google.android.exoplayer2.upstream.Allocator;
|
import com.google.android.exoplayer2.upstream.Allocator;
|
||||||
import com.google.android.exoplayer2.upstream.TransferListener;
|
import com.google.android.exoplayer2.upstream.TransferListener;
|
||||||
import com.google.android.exoplayer2.util.Assertions;
|
|
||||||
import com.google.android.exoplayer2.util.Clock;
|
import com.google.android.exoplayer2.util.Clock;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
@ -72,6 +74,7 @@ import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.robolectric.annotation.LooperMode;
|
import org.robolectric.annotation.LooperMode;
|
||||||
|
import org.robolectric.shadows.ShadowAudioManager;
|
||||||
|
|
||||||
/** Unit test for {@link ExoPlayer}. */
|
/** Unit test for {@link ExoPlayer}. */
|
||||||
@RunWith(AndroidJUnit4.class)
|
@RunWith(AndroidJUnit4.class)
|
||||||
|
|
@ -2796,6 +2799,39 @@ public final class ExoPlayerTest {
|
||||||
assertThat(seenPlaybackSuppression.get()).isFalse();
|
assertThat(seenPlaybackSuppression.get()).isFalse();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void audioFocusDenied() throws Exception {
|
||||||
|
ShadowAudioManager shadowAudioManager = shadowOf(context.getSystemService(AudioManager.class));
|
||||||
|
shadowAudioManager.setNextFocusRequestResponse(AudioManager.AUDIOFOCUS_REQUEST_FAILED);
|
||||||
|
|
||||||
|
PlayerStateGrabber playerStateGrabber = new PlayerStateGrabber();
|
||||||
|
ActionSchedule actionSchedule =
|
||||||
|
new ActionSchedule.Builder("audioFocusDenied")
|
||||||
|
.setAudioAttributes(AudioAttributes.DEFAULT, /* handleAudioFocus= */ true)
|
||||||
|
.play()
|
||||||
|
.waitForPlaybackState(Player.STATE_READY)
|
||||||
|
.executeRunnable(playerStateGrabber)
|
||||||
|
.build();
|
||||||
|
AtomicBoolean seenPlaybackSuppression = new AtomicBoolean();
|
||||||
|
EventListener listener =
|
||||||
|
new EventListener() {
|
||||||
|
@Override
|
||||||
|
public void onPlaybackSuppressionReasonChanged(
|
||||||
|
@Player.PlaybackSuppressionReason int playbackSuppressionReason) {
|
||||||
|
seenPlaybackSuppression.set(true);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
new ExoPlayerTestRunner.Builder()
|
||||||
|
.setActionSchedule(actionSchedule)
|
||||||
|
.setEventListener(listener)
|
||||||
|
.build(context)
|
||||||
|
.start()
|
||||||
|
.blockUntilActionScheduleFinished(TIMEOUT_MS);
|
||||||
|
|
||||||
|
assertThat(playerStateGrabber.playWhenReady).isFalse();
|
||||||
|
assertThat(seenPlaybackSuppression.get()).isFalse();
|
||||||
|
}
|
||||||
|
|
||||||
// Internal methods.
|
// Internal methods.
|
||||||
|
|
||||||
private static ActionSchedule.Builder addSurfaceSwitch(ActionSchedule.Builder builder) {
|
private static ActionSchedule.Builder addSurfaceSwitch(ActionSchedule.Builder builder) {
|
||||||
|
|
@ -2841,38 +2877,17 @@ public final class ExoPlayerTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private static final class PlayerStateGrabber extends PlayerRunnable {
|
||||||
* Provides a wrapper for a {@link Runnable} which does collect playback states and window counts.
|
|
||||||
* Can be used with {@link ActionSchedule.Builder#executeRunnable(Runnable)} to verify that a
|
|
||||||
* playback state did not change and hence no observable callback is called.
|
|
||||||
*
|
|
||||||
* <p>This is specifically useful in cases when the test may end before a given state arrives or
|
|
||||||
* when an action of the action schedule might execute before a callback is called.
|
|
||||||
*/
|
|
||||||
public static class PlaybackStateCollector extends PlayerRunnable {
|
|
||||||
|
|
||||||
private final int[] playbackStates;
|
public boolean playWhenReady;
|
||||||
private final int[] timelineWindowCount;
|
@Player.State public int playbackState;
|
||||||
private final int index;
|
@Nullable public Timeline timeline;
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates the collector.
|
|
||||||
*
|
|
||||||
* @param index The index to populate.
|
|
||||||
* @param playbackStates An array of playback states to populate.
|
|
||||||
* @param timelineWindowCount An array of window counts to populate.
|
|
||||||
*/
|
|
||||||
public PlaybackStateCollector(int index, int[] playbackStates, int[] timelineWindowCount) {
|
|
||||||
Assertions.checkArgument(playbackStates.length > index && timelineWindowCount.length > index);
|
|
||||||
this.playbackStates = playbackStates;
|
|
||||||
this.timelineWindowCount = timelineWindowCount;
|
|
||||||
this.index = index;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run(SimpleExoPlayer player) {
|
public void run(SimpleExoPlayer player) {
|
||||||
playbackStates[index] = player.getPlaybackState();
|
playWhenReady = player.getPlayWhenReady();
|
||||||
timelineWindowCount[index] = player.getCurrentTimeline().getWindowCount();
|
playbackState = player.getPlaybackState();
|
||||||
|
timeline = player.getCurrentTimeline();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue