Commit 88e356f2 by samrobinson Committed by kim-vde

Add `WifiLock` management to `SimpleExoPlayer`.

Issue:#6914
PiperOrigin-RevId: 297598910
parent 292942fe
...@@ -39,6 +39,8 @@ ...@@ -39,6 +39,8 @@
`Format.copyWith*` methods. `Format.copyWith*` methods.
* Split `Format.bitrate` into `Format.averageBitrate` and `Format.peakBitrate` * Split `Format.bitrate` into `Format.averageBitrate` and `Format.peakBitrate`
([#2863](https://github.com/google/ExoPlayer/issues/2863)). ([#2863](https://github.com/google/ExoPlayer/issues/2863)).
* Add optional automatic `WifiLock` handling to `SimpleExoPlayer`
([#6914](https://github.com/google/ExoPlayer/issues/6914)).
* Text: * Text:
* Parse `<ruby>` and `<rt>` tags in WebVTT subtitles (rendering is coming * Parse `<ruby>` and `<rt>` tags in WebVTT subtitles (rendering is coming
later). later).
......
...@@ -962,6 +962,37 @@ public final class C { ...@@ -962,6 +962,37 @@ public final class C {
public static final int NETWORK_TYPE_OTHER = 8; public static final int NETWORK_TYPE_OTHER = 8;
/** /**
* Mode specifying whether the player should hold a WakeLock and a WifiLock. One of {@link
* #WAKE_MODE_NONE}, {@link #WAKE_MODE_LOCAL} and {@link #WAKE_MODE_NETWORK}.
*/
@Documented
@Retention(RetentionPolicy.SOURCE)
@IntDef({WAKE_MODE_NONE, WAKE_MODE_LOCAL, WAKE_MODE_NETWORK})
public @interface WakeMode {}
/**
* A wake mode that will not cause the player to hold any locks.
*
* <p>This is suitable for applications that do not play media with the screen off.
*/
public static final int WAKE_MODE_NONE = 0;
/**
* A wake mode that will cause the player to hold a {@link android.os.PowerManager.WakeLock}
* during playback.
*
* <p>This is suitable for applications that play media with the screen off and do not load media
* over wifi.
*/
public static final int WAKE_MODE_LOCAL = 1;
/**
* A wake mode that will cause the player to hold a {@link android.os.PowerManager.WakeLock} and a
* {@link android.net.wifi.WifiManager.WifiLock} during playback.
*
* <p>This is suitable for applications that play media with the screen off and may load media
* over wifi.
*/
public static final int WAKE_MODE_NETWORK = 2;
/**
* Track role flags. Possible flag values are {@link #ROLE_FLAG_MAIN}, {@link * Track role flags. Possible flag values are {@link #ROLE_FLAG_MAIN}, {@link
* #ROLE_FLAG_ALTERNATE}, {@link #ROLE_FLAG_SUPPLEMENTARY}, {@link #ROLE_FLAG_COMMENTARY}, {@link * #ROLE_FLAG_ALTERNATE}, {@link #ROLE_FLAG_SUPPLEMENTARY}, {@link #ROLE_FLAG_COMMENTARY}, {@link
* #ROLE_FLAG_DUB}, {@link #ROLE_FLAG_EMERGENCY}, {@link #ROLE_FLAG_CAPTION}, {@link * #ROLE_FLAG_DUB}, {@link #ROLE_FLAG_EMERGENCY}, {@link #ROLE_FLAG_CAPTION}, {@link
......
...@@ -317,6 +317,7 @@ public class SimpleExoPlayer extends BasePlayer ...@@ -317,6 +317,7 @@ public class SimpleExoPlayer extends BasePlayer
private final AudioBecomingNoisyManager audioBecomingNoisyManager; private final AudioBecomingNoisyManager audioBecomingNoisyManager;
private final AudioFocusManager audioFocusManager; private final AudioFocusManager audioFocusManager;
private final WakeLockManager wakeLockManager; private final WakeLockManager wakeLockManager;
private final WifiLockManager wifiLockManager;
@Nullable private Format videoFormat; @Nullable private Format videoFormat;
@Nullable private Format audioFormat; @Nullable private Format audioFormat;
...@@ -432,6 +433,7 @@ public class SimpleExoPlayer extends BasePlayer ...@@ -432,6 +433,7 @@ public class SimpleExoPlayer extends BasePlayer
new AudioBecomingNoisyManager(context, eventHandler, componentListener); new AudioBecomingNoisyManager(context, eventHandler, componentListener);
audioFocusManager = new AudioFocusManager(context, eventHandler, componentListener); audioFocusManager = new AudioFocusManager(context, eventHandler, componentListener);
wakeLockManager = new WakeLockManager(context); wakeLockManager = new WakeLockManager(context);
wifiLockManager = new WifiLockManager(context);
} }
@Override @Override
...@@ -1395,6 +1397,7 @@ public class SimpleExoPlayer extends BasePlayer ...@@ -1395,6 +1397,7 @@ public class SimpleExoPlayer extends BasePlayer
audioBecomingNoisyManager.setEnabled(false); audioBecomingNoisyManager.setEnabled(false);
audioFocusManager.handleStop(); audioFocusManager.handleStop();
wakeLockManager.setStayAwake(false); wakeLockManager.setStayAwake(false);
wifiLockManager.setStayAwake(false);
player.release(); player.release();
removeSurfaceCallbacks(); removeSurfaceCallbacks();
if (surface != null) { if (surface != null) {
...@@ -1529,9 +1532,45 @@ public class SimpleExoPlayer extends BasePlayer ...@@ -1529,9 +1532,45 @@ public class SimpleExoPlayer extends BasePlayer
* *
* @param handleWakeLock Whether the player should use a {@link android.os.PowerManager.WakeLock} * @param handleWakeLock Whether the player should use a {@link android.os.PowerManager.WakeLock}
* to ensure the device stays awake for playback, even when the screen is off. * to ensure the device stays awake for playback, even when the screen is off.
* @deprecated Use {@link #setWakeMode(int)} instead.
*/ */
@Deprecated
public void setHandleWakeLock(boolean handleWakeLock) { public void setHandleWakeLock(boolean handleWakeLock) {
wakeLockManager.setEnabled(handleWakeLock); setWakeMode(handleWakeLock ? C.WAKE_MODE_LOCAL : C.WAKE_MODE_NONE);
}
/**
* Sets how the player should keep the device awake for playback when the screen is off.
*
* <p>Enabling this feature requires the {@link android.Manifest.permission#WAKE_LOCK} permission.
* It should be used together with a foreground {@link android.app.Service} for use cases where
* playback occurs and the screen is off (e.g. background audio playback). It is not useful when
* the screen will be kept on during playback (e.g. foreground video playback).
*
* <p>When enabled, the locks ({@link android.os.PowerManager.WakeLock} / {@link
* android.net.wifi.WifiManager.WifiLock}) will be held whenever the player is in the {@link
* #STATE_READY} or {@link #STATE_BUFFERING} states with {@code playWhenReady = true}. The locks
* held depends on the specified {@link C.WakeMode}.
*
* @param wakeMode The {@link C.WakeMode} option to keep the device awake during playback.
*/
public void setWakeMode(@C.WakeMode int wakeMode) {
switch (wakeMode) {
case C.WAKE_MODE_NONE:
wakeLockManager.setEnabled(false);
wifiLockManager.setEnabled(false);
break;
case C.WAKE_MODE_LOCAL:
wakeLockManager.setEnabled(true);
wifiLockManager.setEnabled(false);
break;
case C.WAKE_MODE_NETWORK:
wakeLockManager.setEnabled(true);
wifiLockManager.setEnabled(true);
break;
default:
break;
}
} }
// Internal methods. // Internal methods.
...@@ -1644,16 +1683,18 @@ public class SimpleExoPlayer extends BasePlayer ...@@ -1644,16 +1683,18 @@ public class SimpleExoPlayer extends BasePlayer
} }
} }
private void updateWakeLock() { private void updateWakeAndWifiLock() {
@State int playbackState = getPlaybackState(); @State int playbackState = getPlaybackState();
switch (playbackState) { switch (playbackState) {
case Player.STATE_READY: case Player.STATE_READY:
case Player.STATE_BUFFERING: case Player.STATE_BUFFERING:
wakeLockManager.setStayAwake(getPlayWhenReady()); wakeLockManager.setStayAwake(getPlayWhenReady());
wifiLockManager.setStayAwake(getPlayWhenReady());
break; break;
case Player.STATE_ENDED: case Player.STATE_ENDED:
case Player.STATE_IDLE: case Player.STATE_IDLE:
wakeLockManager.setStayAwake(false); wakeLockManager.setStayAwake(false);
wifiLockManager.setStayAwake(false);
break; break;
default: default:
throw new IllegalStateException(); throw new IllegalStateException();
...@@ -1951,13 +1992,13 @@ public class SimpleExoPlayer extends BasePlayer ...@@ -1951,13 +1992,13 @@ public class SimpleExoPlayer extends BasePlayer
@Override @Override
public void onPlaybackStateChanged(@State int playbackState) { public void onPlaybackStateChanged(@State int playbackState) {
updateWakeLock(); updateWakeAndWifiLock();
} }
@Override @Override
public void onPlayWhenReadyChanged( public void onPlayWhenReadyChanged(
boolean playWhenReady, @PlayWhenReadyChangeReason int reason) { boolean playWhenReady, @PlayWhenReadyChangeReason int reason) {
updateWakeLock(); updateWakeAndWifiLock();
} }
} }
} }
...@@ -39,7 +39,8 @@ import com.google.android.exoplayer2.util.Log; ...@@ -39,7 +39,8 @@ import com.google.android.exoplayer2.util.Log;
private boolean stayAwake; private boolean stayAwake;
public WakeLockManager(Context context) { public WakeLockManager(Context context) {
powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE); powerManager =
(PowerManager) context.getApplicationContext().getSystemService(Context.POWER_SERVICE);
} }
/** /**
...@@ -48,15 +49,15 @@ import com.google.android.exoplayer2.util.Log; ...@@ -48,15 +49,15 @@ import com.google.android.exoplayer2.util.Log;
* <p>By default, wake lock handling is not enabled. Enabling this will acquire the wake lock if * <p>By default, wake lock handling is not enabled. Enabling this will acquire the wake lock if
* necessary. Disabling this will release the wake lock if it is held. * necessary. Disabling this will release the wake lock if it is held.
* *
* @param enabled True if the player should handle a {@link WakeLock}, false otherwise. Please * <p>Enabling {@link WakeLock} requires the {@link android.Manifest.permission#WAKE_LOCK}.
* note that enabling this requires the {@link android.Manifest.permission#WAKE_LOCK} *
* permission. * @param enabled True if the player should handle a {@link WakeLock}, false otherwise.
*/ */
public void setEnabled(boolean enabled) { public void setEnabled(boolean enabled) {
if (enabled) { if (enabled) {
if (wakeLock == null) { if (wakeLock == null) {
if (powerManager == null) { if (powerManager == null) {
Log.w(TAG, "PowerManager was null, therefore the WakeLock was not created."); Log.w(TAG, "PowerManager is null, therefore not creating the WakeLock.");
return; return;
} }
wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKE_LOCK_TAG); wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKE_LOCK_TAG);
...@@ -86,8 +87,10 @@ import com.google.android.exoplayer2.util.Log; ...@@ -86,8 +87,10 @@ import com.google.android.exoplayer2.util.Log;
// reasonable timeout that would not affect the user. // reasonable timeout that would not affect the user.
@SuppressLint("WakelockTimeout") @SuppressLint("WakelockTimeout")
private void updateWakeLock() { private void updateWakeLock() {
// Needed for the library nullness check. If enabled is true, the wakelock will not be null. if (wakeLock == null) {
if (wakeLock != null) { return;
}
if (enabled && stayAwake) { if (enabled && stayAwake) {
if (!wakeLock.isHeld()) { if (!wakeLock.isHeld()) {
wakeLock.acquire(); wakeLock.acquire();
...@@ -96,5 +99,4 @@ import com.google.android.exoplayer2.util.Log; ...@@ -96,5 +99,4 @@ import com.google.android.exoplayer2.util.Log;
wakeLock.release(); wakeLock.release();
} }
} }
}
} }
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.android.exoplayer2;
import android.content.Context;
import android.net.wifi.WifiManager;
import android.net.wifi.WifiManager.WifiLock;
import androidx.annotation.Nullable;
import com.google.android.exoplayer2.util.Log;
/**
* Handles a {@link WifiLock}
*
* <p>The handling of wifi locks requires the {@link android.Manifest.permission#WAKE_LOCK}
* permission.
*/
/* package */ final class WifiLockManager {
private static final String TAG = "WifiLockManager";
private static final String WIFI_LOCK_TAG = "ExoPlayer:WifiLockManager";
@Nullable private final WifiManager wifiManager;
@Nullable private WifiLock wifiLock;
private boolean enabled;
private boolean stayAwake;
public WifiLockManager(Context context) {
wifiManager =
(WifiManager) context.getApplicationContext().getSystemService(Context.WIFI_SERVICE);
}
/**
* Sets whether to enable the usage of a {@link WifiLock}.
*
* <p>By default, wifi lock handling is not enabled. Enabling will acquire the wifi lock if
* necessary. Disabling will release the wifi lock if held.
*
* <p>Enabling {@link WifiLock} requires the {@link android.Manifest.permission#WAKE_LOCK}.
*
* @param enabled True if the player should handle a {@link WifiLock}.
*/
public void setEnabled(boolean enabled) {
if (enabled && wifiLock == null) {
if (wifiManager == null) {
Log.w(TAG, "WifiManager is null, therefore not creating the WifiLock.");
return;
}
wifiLock = wifiManager.createWifiLock(WifiManager.WIFI_MODE_FULL_HIGH_PERF, WIFI_LOCK_TAG);
}
this.enabled = enabled;
updateWifiLock();
}
/**
* Sets whether to acquire or release the {@link WifiLock}.
*
* <p>The wifi lock will not be acquired unless handling has been enabled through {@link
* #setEnabled(boolean)}.
*
* @param stayAwake True if the player should acquire the {@link WifiLock}. False if it should
* release.
*/
public void setStayAwake(boolean stayAwake) {
this.stayAwake = stayAwake;
updateWifiLock();
}
private void updateWifiLock() {
if (wifiLock == null) {
return;
}
if (enabled && stayAwake) {
if (!wifiLock.isHeld()) {
wifiLock.acquire();
}
} else if (wifiLock.isHeld()) {
wifiLock.release();
}
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment