1515 */
1616package androidx .media3 .exoplayer ;
1717
18+ import android .Manifest ;
1819import android .content .Context ;
20+ import android .content .pm .PackageManager ;
1921import android .net .wifi .WifiManager ;
2022import android .net .wifi .WifiManager .WifiLock ;
2123import android .os .Looper ;
22- import androidx .annotation .Nullable ;
2324import androidx .media3 .common .util .Clock ;
2425import androidx .media3 .common .util .HandlerWrapper ;
2526import androidx .media3 .common .util .Log ;
27+ import org .checkerframework .checker .nullness .qual .MonotonicNonNull ;
2628
2729/**
2830 * Handles a {@link WifiLock}
3436
3537 private static final String TAG = "WifiLockManager" ;
3638 private static final String WIFI_LOCK_TAG = "ExoPlayer:WifiLockManager" ;
39+ private static final int UNREACTIVE_WIFILOCK_HANDLER_RELEASE_DELAY_MS = 1000 ;
3740
3841 private final WifiLockManagerInternal wifiLockManagerInternal ;
3942 private final HandlerWrapper wifiLockHandler ;
43+ private final HandlerWrapper mainHandler ;
4044
4145 private boolean enabled ;
4246 private boolean stayAwake ;
5155 public WifiLockManager (Context context , Looper wifiLockLooper , Clock clock ) {
5256 wifiLockManagerInternal = new WifiLockManagerInternal (context .getApplicationContext ());
5357 wifiLockHandler = clock .createHandler (wifiLockLooper , /* callback= */ null );
58+ mainHandler = clock .createHandler (Looper .getMainLooper (), /* callback= */ null );
5459 }
5560
5661 /**
@@ -68,8 +73,7 @@ public void setEnabled(boolean enabled) {
6873 return ;
6974 }
7075 this .enabled = enabled ;
71- boolean stayAwakeCurrent = stayAwake ;
72- wifiLockHandler .post (() -> wifiLockManagerInternal .updateWifiLock (enabled , stayAwakeCurrent ));
76+ postUpdateWifiLock (enabled , stayAwake );
7377 }
7478
7579 /**
@@ -87,24 +91,48 @@ public void setStayAwake(boolean stayAwake) {
8791 }
8892 this .stayAwake = stayAwake ;
8993 if (enabled ) {
94+ postUpdateWifiLock (/* enabled= */ true , stayAwake );
95+ }
96+ }
97+
98+ private void postUpdateWifiLock (boolean enabled , boolean stayAwake ) {
99+ if (shouldAcquireWifilock (enabled , stayAwake )) {
100+ wifiLockHandler .post (() -> wifiLockManagerInternal .updateWifiLock (enabled , stayAwake ));
101+ } else {
102+ // When we are about to release a Wifi lock, add emergency safeguard on main thread in case
103+ // the lock handler thread is unresponsive.
104+ Runnable emergencyRelease = wifiLockManagerInternal ::forceReleaseWifiLock ;
105+ mainHandler .postDelayed (emergencyRelease , UNREACTIVE_WIFILOCK_HANDLER_RELEASE_DELAY_MS );
90106 wifiLockHandler .post (
91- () -> wifiLockManagerInternal .updateWifiLock (/* enabled= */ true , stayAwake ));
107+ () -> {
108+ mainHandler .removeCallbacks (emergencyRelease );
109+ wifiLockManagerInternal .updateWifiLock (enabled , stayAwake );
110+ });
92111 }
93112 }
94113
114+ private static boolean shouldAcquireWifilock (boolean enabled , boolean stayAwake ) {
115+ return enabled && stayAwake ;
116+ }
117+
95118 /** Internal methods called on the wifi lock Looper. */
96119 private static final class WifiLockManagerInternal {
97120
98121 private final Context applicationContext ;
99122
100- @ Nullable private WifiLock wifiLock ;
123+ private @ MonotonicNonNull WifiLock wifiLock ;
101124
102125 public WifiLockManagerInternal (Context applicationContext ) {
103126 this .applicationContext = applicationContext ;
104127 }
105128
106129 public void updateWifiLock (boolean enabled , boolean stayAwake ) {
107130 if (enabled && wifiLock == null ) {
131+ if (applicationContext .checkSelfPermission (Manifest .permission .WAKE_LOCK )
132+ != PackageManager .PERMISSION_GRANTED ) {
133+ Log .w (TAG , "WAKE_LOCK permission not granted, can't acquire wake lock for playback" );
134+ return ;
135+ }
108136 WifiManager wifiManager =
109137 (WifiManager )
110138 applicationContext .getApplicationContext ().getSystemService (Context .WIFI_SERVICE );
@@ -120,11 +148,17 @@ public void updateWifiLock(boolean enabled, boolean stayAwake) {
120148 return ;
121149 }
122150
123- if (enabled && stayAwake ) {
151+ if (shouldAcquireWifilock ( enabled , stayAwake ) ) {
124152 wifiLock .acquire ();
125153 } else {
126154 wifiLock .release ();
127155 }
128156 }
157+
158+ private synchronized void forceReleaseWifiLock () {
159+ if (wifiLock != null ) {
160+ wifiLock .release ();
161+ }
162+ }
129163 }
130164}
0 commit comments