Skip to content

Commit

Permalink
Add WifiLock management to SimpleExoPlayer.
Browse files Browse the repository at this point in the history
Issue:#6914
PiperOrigin-RevId: 297598910
  • Loading branch information
Samrobbo authored and kim-vde committed Feb 27, 2020
1 parent 292942f commit 88e356f
Show file tree
Hide file tree
Showing 5 changed files with 188 additions and 17 deletions.
2 changes: 2 additions & 0 deletions RELEASENOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@
`Format.copyWith*` methods.
* Split `Format.bitrate` into `Format.averageBitrate` and `Format.peakBitrate`
([#2863](https://github.com/google/ExoPlayer/issues/2863)).
* Add optional automatic `WifiLock` handling to `SimpleExoPlayer`
([#6914](https://github.com/google/ExoPlayer/issues/6914)).
* Text:
* Parse `<ruby>` and `<rt>` tags in WebVTT subtitles (rendering is coming
later).
Expand Down
31 changes: 31 additions & 0 deletions library/common/src/main/java/com/google/android/exoplayer2/C.java
Original file line number Diff line number Diff line change
Expand Up @@ -961,6 +961,37 @@ private C() {}
/** Network type for other connections which are not Wifi or cellular (e.g. VPN, Bluetooth). */
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
* #ROLE_FLAG_ALTERNATE}, {@link #ROLE_FLAG_SUPPLEMENTARY}, {@link #ROLE_FLAG_COMMENTARY}, {@link
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,7 @@ public SimpleExoPlayer build() {
private final AudioBecomingNoisyManager audioBecomingNoisyManager;
private final AudioFocusManager audioFocusManager;
private final WakeLockManager wakeLockManager;
private final WifiLockManager wifiLockManager;

@Nullable private Format videoFormat;
@Nullable private Format audioFormat;
Expand Down Expand Up @@ -432,6 +433,7 @@ protected SimpleExoPlayer(
new AudioBecomingNoisyManager(context, eventHandler, componentListener);
audioFocusManager = new AudioFocusManager(context, eventHandler, componentListener);
wakeLockManager = new WakeLockManager(context);
wifiLockManager = new WifiLockManager(context);
}

@Override
Expand Down Expand Up @@ -1395,6 +1397,7 @@ public void release() {
audioBecomingNoisyManager.setEnabled(false);
audioFocusManager.handleStop();
wakeLockManager.setStayAwake(false);
wifiLockManager.setStayAwake(false);
player.release();
removeSurfaceCallbacks();
if (surface != null) {
Expand Down Expand Up @@ -1529,9 +1532,45 @@ public long getContentBufferedPosition() {
*
* @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.
* @deprecated Use {@link #setWakeMode(int)} instead.
*/
@Deprecated
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.
Expand Down Expand Up @@ -1644,16 +1683,18 @@ private void verifyApplicationThread() {
}
}

private void updateWakeLock() {
private void updateWakeAndWifiLock() {
@State int playbackState = getPlaybackState();
switch (playbackState) {
case Player.STATE_READY:
case Player.STATE_BUFFERING:
wakeLockManager.setStayAwake(getPlayWhenReady());
wifiLockManager.setStayAwake(getPlayWhenReady());
break;
case Player.STATE_ENDED:
case Player.STATE_IDLE:
wakeLockManager.setStayAwake(false);
wifiLockManager.setStayAwake(false);
break;
default:
throw new IllegalStateException();
Expand Down Expand Up @@ -1951,13 +1992,13 @@ public void onIsLoadingChanged(boolean isLoading) {

@Override
public void onPlaybackStateChanged(@State int playbackState) {
updateWakeLock();
updateWakeAndWifiLock();
}

@Override
public void onPlayWhenReadyChanged(
boolean playWhenReady, @PlayWhenReadyChangeReason int reason) {
updateWakeLock();
updateWakeAndWifiLock();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@
private boolean stayAwake;

public WakeLockManager(Context context) {
powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
powerManager =
(PowerManager) context.getApplicationContext().getSystemService(Context.POWER_SERVICE);
}

/**
Expand All @@ -48,15 +49,15 @@ public WakeLockManager(Context context) {
* <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.
*
* @param enabled True if the player should handle a {@link WakeLock}, false otherwise. Please
* note that enabling this requires the {@link android.Manifest.permission#WAKE_LOCK}
* permission.
* <p>Enabling {@link WakeLock} requires the {@link android.Manifest.permission#WAKE_LOCK}.
*
* @param enabled True if the player should handle a {@link WakeLock}, false otherwise.
*/
public void setEnabled(boolean enabled) {
if (enabled) {
if (wakeLock == 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;
}
wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKE_LOCK_TAG);
Expand Down Expand Up @@ -86,15 +87,16 @@ public void setStayAwake(boolean stayAwake) {
// reasonable timeout that would not affect the user.
@SuppressLint("WakelockTimeout")
private void updateWakeLock() {
// Needed for the library nullness check. If enabled is true, the wakelock will not be null.
if (wakeLock != null) {
if (enabled && stayAwake) {
if (!wakeLock.isHeld()) {
wakeLock.acquire();
}
} else if (wakeLock.isHeld()) {
wakeLock.release();
if (wakeLock == null) {
return;
}

if (enabled && stayAwake) {
if (!wakeLock.isHeld()) {
wakeLock.acquire();
}
} else if (wakeLock.isHeld()) {
wakeLock.release();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
/*
* 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();
}
}
}

0 comments on commit 88e356f

Please sign in to comment.