diff --git a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java index 26357a18dc..47ee6b062c 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java @@ -659,7 +659,14 @@ import java.util.concurrent.TimeoutException; public void setForegroundMode(boolean foregroundMode) { if (this.foregroundMode != foregroundMode) { this.foregroundMode = foregroundMode; - internalPlayer.setForegroundMode(foregroundMode); + if (!internalPlayer.setForegroundMode(foregroundMode)) { + notifyListeners( + listener -> + listener.onPlayerError( + ExoPlaybackException.createForUnexpected( + new RuntimeException( + new TimeoutException("Setting foreground mode timed out."))))); + } } } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java index 53c8a5d080..f7abd4dd9d 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java @@ -43,6 +43,7 @@ import com.google.android.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.Clock; import com.google.android.exoplayer2.util.HandlerWrapper; import com.google.android.exoplayer2.util.Log; +import com.google.android.exoplayer2.util.Supplier; import com.google.android.exoplayer2.util.TraceUtil; import com.google.android.exoplayer2.util.Util; import java.io.IOException; @@ -296,29 +297,24 @@ import java.util.concurrent.atomic.AtomicBoolean; handler.obtainMessage(MSG_SEND_MESSAGE, message).sendToTarget(); } - public synchronized void setForegroundMode(boolean foregroundMode) { + public synchronized boolean setForegroundMode(boolean foregroundMode) { if (released || !internalPlaybackThread.isAlive()) { - return; + return true; } if (foregroundMode) { handler.obtainMessage(MSG_SET_FOREGROUND_MODE, /* foregroundMode */ 1, 0).sendToTarget(); + return true; } else { AtomicBoolean processedFlag = new AtomicBoolean(); handler .obtainMessage(MSG_SET_FOREGROUND_MODE, /* foregroundMode */ 0, 0, processedFlag) .sendToTarget(); - boolean wasInterrupted = false; - while (!processedFlag.get()) { - try { - wait(); - } catch (InterruptedException e) { - wasInterrupted = true; - } - } - if (wasInterrupted) { - // Restore the interrupted status. - Thread.currentThread().interrupt(); + if (releaseTimeoutMs > 0) { + waitUninterruptibly(/* condition= */ processedFlag::get, releaseTimeoutMs); + } else { + waitUninterruptibly(/* condition= */ processedFlag::get); } + return processedFlag.get(); } } @@ -328,16 +324,11 @@ import java.util.concurrent.atomic.AtomicBoolean; } handler.sendEmptyMessage(MSG_RELEASE); - try { - if (releaseTimeoutMs > 0) { - waitUntilReleased(releaseTimeoutMs); - } else { - waitUntilReleased(); - } - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); + if (releaseTimeoutMs > 0) { + waitUninterruptibly(/* condition= */ () -> released, releaseTimeoutMs); + } else { + waitUninterruptibly(/* condition= */ () -> released); } - return released; } @@ -505,59 +496,54 @@ import java.util.concurrent.atomic.AtomicBoolean; // Private methods. /** - * Blocks the current thread until {@link #releaseInternal()} is executed on the playback Thread. + * Blocks the current thread until a condition becomes true. * - *

If the current thread is interrupted while waiting for {@link #releaseInternal()} to - * complete, this method will delay throwing the {@link InterruptedException} to ensure that the - * underlying resources have been released, and will an {@link InterruptedException} after - * {@link #releaseInternal()} is complete. + *

If the current thread is interrupted while waiting for the condition to become true, this + * method will restore the interrupt after the condition became true. * - * @throws {@link InterruptedException} if the current Thread was interrupted while waiting for - * {@link #releaseInternal()} to complete. + * @param condition The condition. */ - private synchronized void waitUntilReleased() throws InterruptedException { - InterruptedException interruptedException = null; - while (!released) { + private synchronized void waitUninterruptibly(Supplier condition) { + boolean wasInterrupted = false; + while (!condition.get()) { try { wait(); } catch (InterruptedException e) { - interruptedException = e; + wasInterrupted = true; } } - - if (interruptedException != null) { - throw interruptedException; + if (wasInterrupted) { + // Restore the interrupted status. + Thread.currentThread().interrupt(); } } /** - * Blocks the current thread until {@link #releaseInternal()} is performed on the playback Thread - * or the specified amount of time has elapsed. + * Blocks the current thread until a condition becomes true or the specified amount of time has + * elapsed. * - *

If the current thread is interrupted while waiting for {@link #releaseInternal()} to - * complete, this method will delay throwing the {@link InterruptedException} to ensure that the - * underlying resources have been released or the operation timed out, and will throw an {@link - * InterruptedException} afterwards. + *

If the current thread is interrupted while waiting for the condition to become true, this + * method will restore the interrupt after the condition became true or the operation times + * out. * - * @param timeoutMs the time in milliseconds to wait for {@link #releaseInternal()} to complete. - * @throws {@link InterruptedException} if the current Thread was interrupted while waiting for - * {@link #releaseInternal()} to complete. + * @param condition The condition. + * @param timeoutMs The time in milliseconds to wait for the condition to become true. */ - private synchronized void waitUntilReleased(long timeoutMs) throws InterruptedException { + private synchronized void waitUninterruptibly(Supplier condition, long timeoutMs) { long deadlineMs = clock.elapsedRealtime() + timeoutMs; long remainingMs = timeoutMs; - InterruptedException interruptedException = null; - while (!released && remainingMs > 0) { + boolean wasInterrupted = false; + while (!condition.get() && remainingMs > 0) { try { wait(remainingMs); } catch (InterruptedException e) { - interruptedException = e; + wasInterrupted = true; } remainingMs = deadlineMs - clock.elapsedRealtime(); } - - if (interruptedException != null) { - throw interruptedException; + if (wasInterrupted) { + // Restore the interrupted status. + Thread.currentThread().interrupt(); } }