Fix call PiP force-expanding and the screen refusing to stay off.

This commit is contained in:
Alex Hart
2026-09-11 14:29:57 -03:00
committed by GitHub
parent 2863d7e1a2
commit 7e569e02c3
3 changed files with 51 additions and 3 deletions
@@ -253,6 +253,10 @@ class WebRtcCallActivity : BaseActivity(), SafetyNumberChangeDialog.Callback, Re
}
override fun onStart() {
// This instance outlived being backgrounded (e.g. the screen was turned off and back on), so any relaunch scheduled in onStop() is unnecessary.
// Cancel it before super.onStart() dispatches the app-foregrounded event, otherwise it would yank the call out of PiP and into fullscreen.
AppDependencies.signalCallManager.cancelPipRelaunch()
super.onStart()
ephemeralStateDisposable = AppDependencies.signalCallManager
@@ -8,6 +8,7 @@ import android.os.Build;
import android.os.ResultReceiver;
import androidx.annotation.AnyThread;
import androidx.annotation.MainThread;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -144,6 +145,7 @@ public final class SignalCallManager implements CallManager.Observer, GroupCall.
private WebRtcServiceState serviceState;
private RxStore<WebRtcEphemeralState> ephemeralStateStore;
private boolean needsToSetSelfUuid = true;
private RelaunchListener pipRelaunchListener;
private RxStore<Map<RecipientId, CallLinkPeekInfo>> linkPeekInfoStore;
@@ -1422,8 +1424,30 @@ public final class SignalCallManager implements CallManager.Observer, GroupCall.
callManager.addAsset(assetGroup, content);
}
/**
* Schedules the call activity to be relaunched in PiP the next time the app is foregrounded. Only relevant if the call activity did not survive being
* backgrounded, e.g. the user dismissed the PiP window or another app's PiP evicted it. If it did survive, {@link #cancelPipRelaunch()} should be called
* to cancel this.
*/
@MainThread
public void relaunchPipOnForeground() {
AppForegroundObserver.addListener(new RelaunchListener(AppForegroundObserver.isForegrounded()));
cancelPipRelaunch();
pipRelaunchListener = new RelaunchListener(AppForegroundObserver.isForegrounded());
AppForegroundObserver.addListener(pipRelaunchListener);
}
/**
* Cancels any pending PiP relaunch scheduled via {@link #relaunchPipOnForeground()}. Relaunching while the call activity is still alive delivers a
* launch-in-PiP intent to it, which pulls it out of PiP and into fullscreen, or forces a deliberately expanded call back into PiP. The former is both
* unprompted and, if it happens while the keyguard is going away, can leave the device wedged in a partially-locked state.
*/
@MainThread
public void cancelPipRelaunch() {
if (pipRelaunchListener != null) {
AppForegroundObserver.removeListener(pipRelaunchListener);
pipRelaunchListener = null;
}
}
private void processSendMessageFailureWithChangeDetection(@NonNull RemotePeer remotePeer,
@@ -1471,6 +1495,9 @@ public final class SignalCallManager implements CallManager.Observer, GroupCall.
});
}
AppForegroundObserver.removeListener(this);
if (pipRelaunchListener == this) {
pipRelaunchListener = null;
}
}
}
@@ -16,6 +16,7 @@ public class LockManager {
private static final String TAG = Log.tag(LockManager.class);
private final PowerManager.WakeLock fullLock;
private final PowerManager.WakeLock fullWakeUpLock;
private final PowerManager.WakeLock partialLock;
private final WifiManager.WifiLock wifiLock;
private final ProximityLock proximityLock;
@@ -33,6 +34,7 @@ public class LockManager {
private enum LockState {
FULL,
FULL_WAKE_UP,
PARTIAL,
SLEEP,
PROXIMITY
@@ -40,7 +42,10 @@ public class LockManager {
public LockManager(Context context) {
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
fullLock = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP, "signal:full");
// These differ only in ACQUIRE_CAUSES_WAKEUP, and must stay separate: these locks are not reference counted, so every acquire() reaches
// PowerManagerService even when already held, and re-applying ACQUIRE_CAUSES_WAKEUP turns the screen back on after the user powered it off.
fullLock = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK, "signal:full");
fullWakeUpLock = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP, "signal:full-wakeup");
partialLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "signal:partial");
proximityLock = new ProximityLock(pm);
@@ -48,6 +53,7 @@ public class LockManager {
wifiLock = wm.createWifiLock(WifiManager.WIFI_MODE_FULL_HIGH_PERF, "signal:wifi");
fullLock.setReferenceCounted(false);
fullWakeUpLock.setReferenceCounted(false);
partialLock.setReferenceCounted(false);
wifiLock.setReferenceCounted(false);
}
@@ -69,7 +75,7 @@ public class LockManager {
setLockState(LockState.PARTIAL);
break;
case INTERACTIVE:
setLockState(LockState.FULL);
setLockState(LockState.FULL_WAKE_UP);
break;
case IN_HANDS_FREE_CALL:
setLockState(LockState.PARTIAL);
@@ -92,16 +98,26 @@ public class LockManager {
fullLock.acquire();
partialLock.acquire();
wifiLock.acquire();
fullWakeUpLock.release();
proximityLock.release();
break;
case FULL_WAKE_UP:
fullWakeUpLock.acquire();
partialLock.acquire();
wifiLock.acquire();
fullLock.release();
proximityLock.release();
break;
case PARTIAL:
partialLock.acquire();
wifiLock.acquire();
fullLock.release();
fullWakeUpLock.release();
proximityLock.release();
break;
case SLEEP:
fullLock.release();
fullWakeUpLock.release();
partialLock.release();
wifiLock.release();
proximityLock.release();
@@ -111,6 +127,7 @@ public class LockManager {
proximityLock.acquire();
wifiLock.acquire();
fullLock.release();
fullWakeUpLock.release();
break;
default:
throw new IllegalArgumentException("Unhandled Mode: " + newState);