From c6de4c76505aabc4f085a464499cd73ad266e7f5 Mon Sep 17 00:00:00 2001 From: Alex Hart Date: Wed, 3 Dec 2025 15:17:43 -0400 Subject: [PATCH] Fix call screen timeout with remote video active. --- .../webrtc/ActiveCallActionProcessorDelegate.java | 15 +++++++++++---- .../webrtc/CallSetupActionProcessorDelegate.java | 8 +++----- .../webrtc/ConnectedCallActionProcessor.java | 9 +++------ .../webrtc/DeviceAwareActionProcessor.java | 13 +++++++------ .../service/webrtc/GroupActionProcessor.java | 11 ++++++++++- .../webrtc/GroupConnectedActionProcessor.java | 4 ++++ .../webrtc/GroupJoiningActionProcessor.java | 10 ++++------ .../securesms/service/webrtc/WebRtcUtil.java | 12 ++++++++++++ 8 files changed, 54 insertions(+), 28 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/ActiveCallActionProcessorDelegate.java b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/ActiveCallActionProcessorDelegate.java index b9553f67f5..e42bcec55a 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/ActiveCallActionProcessorDelegate.java +++ b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/ActiveCallActionProcessorDelegate.java @@ -80,10 +80,17 @@ public class ActiveCallActionProcessorDelegate extends WebRtcActionProcessor { CallParticipant oldParticipant = Objects.requireNonNull(currentState.getCallInfoState().getRemoteCallParticipant(activePeer.getRecipient())); CallParticipant newParticipant = oldParticipant.withVideoEnabled(enable); - return currentState.builder() - .changeCallInfoState() - .putParticipant(activePeer.getRecipient(), newParticipant) - .build(); + currentState = currentState.builder() + .changeCallInfoState() + .putParticipant(activePeer.getRecipient(), newParticipant) + .build(); + + if (currentState.getCallInfoState().getCallState() == WebRtcViewModel.State.CALL_CONNECTED) { + boolean localVideoEnabled = currentState.getLocalDeviceState().getCameraState().isEnabled(); + webRtcInteractor.updatePhoneState(WebRtcUtil.getInCallPhoneState(context, localVideoEnabled, enable)); + } + + return currentState; } @Override diff --git a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/CallSetupActionProcessorDelegate.java b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/CallSetupActionProcessorDelegate.java index dcfb79df75..af1eabe671 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/CallSetupActionProcessorDelegate.java +++ b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/CallSetupActionProcessorDelegate.java @@ -50,11 +50,9 @@ public class CallSetupActionProcessorDelegate extends WebRtcActionProcessor { activePeer.connected(); - if (currentState.getLocalDeviceState().getCameraState().isEnabled()) { - webRtcInteractor.updatePhoneState(LockManager.PhoneState.IN_VIDEO); - } else { - webRtcInteractor.updatePhoneState(WebRtcUtil.getInCallPhoneState(context)); - } + boolean localVideoEnabled = currentState.getLocalDeviceState().getCameraState().isEnabled(); + boolean remoteVideoEnabled = currentState.getCallSetupState(activePeer).isRemoteVideoOffer(); + webRtcInteractor.updatePhoneState(WebRtcUtil.getInCallPhoneState(context, localVideoEnabled, remoteVideoEnabled)); currentState = currentState.builder() .actionProcessor(new ConnectedCallActionProcessor(webRtcInteractor)) diff --git a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/ConnectedCallActionProcessor.java b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/ConnectedCallActionProcessor.java index 0d62250288..76ff21c5c8 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/ConnectedCallActionProcessor.java +++ b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/ConnectedCallActionProcessor.java @@ -14,7 +14,6 @@ import org.thoughtcrime.securesms.events.WebRtcViewModel; import org.thoughtcrime.securesms.ringrtc.RemotePeer; import org.thoughtcrime.securesms.service.webrtc.state.WebRtcEphemeralState; import org.thoughtcrime.securesms.service.webrtc.state.WebRtcServiceState; -import org.thoughtcrime.securesms.webrtc.locks.LockManager; import java.util.Collections; import java.util.Optional; @@ -54,11 +53,9 @@ public class ConnectedCallActionProcessor extends DeviceAwareActionProcessor { .cameraState(currentState.getVideoState().requireCamera().getCameraState()) .build(); - if (currentState.getLocalDeviceState().getCameraState().isEnabled()) { - webRtcInteractor.updatePhoneState(LockManager.PhoneState.IN_VIDEO); - } else { - webRtcInteractor.updatePhoneState(WebRtcUtil.getInCallPhoneState(context)); - } + boolean localVideoEnabled = currentState.getLocalDeviceState().getCameraState().isEnabled(); + boolean remoteVideoEnabled = currentState.getCallInfoState().getRemoteCallParticipantsMap().values().stream().anyMatch(CallParticipant::isVideoEnabled); + webRtcInteractor.updatePhoneState(WebRtcUtil.getInCallPhoneState(context, localVideoEnabled, remoteVideoEnabled)); WebRtcUtil.enableSpeakerPhoneIfNeeded(webRtcInteractor, currentState); diff --git a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/DeviceAwareActionProcessor.java b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/DeviceAwareActionProcessor.java index c02845fb75..0f2598eedf 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/DeviceAwareActionProcessor.java +++ b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/DeviceAwareActionProcessor.java @@ -7,6 +7,7 @@ import org.thoughtcrime.securesms.components.webrtc.BroadcastVideoSink; import org.thoughtcrime.securesms.events.WebRtcViewModel; import org.thoughtcrime.securesms.ringrtc.CameraState; import org.thoughtcrime.securesms.ringrtc.RemotePeer; +import org.thoughtcrime.securesms.events.CallParticipant; import org.thoughtcrime.securesms.service.webrtc.state.WebRtcServiceState; import org.thoughtcrime.securesms.webrtc.audio.SignalAudioManager; @@ -27,12 +28,12 @@ public abstract class DeviceAwareActionProcessor extends WebRtcActionProcessor { protected @NonNull WebRtcServiceState handleAudioDeviceChanged(@NonNull WebRtcServiceState currentState, @NonNull SignalAudioManager.AudioDevice activeDevice, @NonNull Set availableDevices) { Log.i(tag, "handleAudioDeviceChanged(): active: " + activeDevice + " available: " + availableDevices); - if (!currentState.getLocalDeviceState().getCameraState().isEnabled()) { - if (currentState.getCallInfoState().getCallState() == WebRtcViewModel.State.CALL_CONNECTED) { - webRtcInteractor.updatePhoneState(WebRtcUtil.getInCallPhoneState(context)); - } else { - Log.i(tag, "handleAudioDeviceChanged(): call not connected, not updating phone state"); - } + if (currentState.getCallInfoState().getCallState() == WebRtcViewModel.State.CALL_CONNECTED) { + boolean localVideoEnabled = currentState.getLocalDeviceState().getCameraState().isEnabled(); + boolean remoteVideoEnabled = currentState.getCallInfoState().getRemoteCallParticipantsMap().values().stream().anyMatch(CallParticipant::isVideoEnabled); + webRtcInteractor.updatePhoneState(WebRtcUtil.getInCallPhoneState(context, localVideoEnabled, remoteVideoEnabled)); + } else { + Log.i(tag, "handleAudioDeviceChanged(): call not connected, not updating phone state"); } return currentState.builder() diff --git a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/GroupActionProcessor.java b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/GroupActionProcessor.java index 33153150dc..68079ba830 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/GroupActionProcessor.java +++ b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/GroupActionProcessor.java @@ -14,6 +14,7 @@ import org.thoughtcrime.securesms.components.webrtc.BroadcastVideoSink; import org.thoughtcrime.securesms.events.CallParticipant; import org.thoughtcrime.securesms.events.CallParticipantId; import org.thoughtcrime.securesms.events.WebRtcViewModel; +import org.thoughtcrime.securesms.events.WebRtcViewModel.State; import org.thoughtcrime.securesms.groups.GroupManager; import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.recipients.RecipientId; @@ -132,7 +133,15 @@ public class GroupActionProcessor extends DeviceAwareActionProcessor { builder.remoteDevicesCount(remoteDevices.size()); - return builder.build(); + WebRtcServiceState updatedState = builder.build(); + + if (updatedState.getCallInfoState().getCallState() == State.CALL_CONNECTED) { + boolean localVideoEnabled = updatedState.getLocalDeviceState().getCameraState().isEnabled(); + boolean remoteVideoEnabled = updatedState.getCallInfoState().getRemoteCallParticipantsMap().values().stream().anyMatch(CallParticipant::isVideoEnabled); + webRtcInteractor.updatePhoneState(WebRtcUtil.getInCallPhoneState(context, localVideoEnabled, remoteVideoEnabled)); + } + + return updatedState; } @Override diff --git a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/GroupConnectedActionProcessor.java b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/GroupConnectedActionProcessor.java index b9720c51f8..a9eb1f7ff8 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/GroupConnectedActionProcessor.java +++ b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/GroupConnectedActionProcessor.java @@ -103,6 +103,10 @@ public class GroupConnectedActionProcessor extends GroupActionProcessor { .cameraState(camera.getCameraState()) .build(); + boolean localVideoEnabled = currentState.getLocalDeviceState().getCameraState().isEnabled(); + boolean remoteVideoEnabled = currentState.getCallInfoState().getRemoteCallParticipantsMap().values().stream().anyMatch(CallParticipant::isVideoEnabled); + webRtcInteractor.updatePhoneState(WebRtcUtil.getInCallPhoneState(context, localVideoEnabled, remoteVideoEnabled)); + WebRtcUtil.enableSpeakerPhoneIfNeeded(webRtcInteractor, currentState); return currentState; diff --git a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/GroupJoiningActionProcessor.java b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/GroupJoiningActionProcessor.java index cd61ac9470..bcdd9714f4 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/GroupJoiningActionProcessor.java +++ b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/GroupJoiningActionProcessor.java @@ -12,9 +12,9 @@ import org.thoughtcrime.securesms.events.WebRtcViewModel; import org.thoughtcrime.securesms.ringrtc.Camera; import org.thoughtcrime.securesms.ringrtc.RemotePeer; import org.thoughtcrime.securesms.service.webrtc.state.WebRtcServiceState; +import org.thoughtcrime.securesms.events.CallParticipant; import org.thoughtcrime.securesms.service.webrtc.state.WebRtcServiceStateBuilder; import org.thoughtcrime.securesms.util.NetworkUtil; -import org.thoughtcrime.securesms.webrtc.locks.LockManager; import static org.thoughtcrime.securesms.webrtc.CallNotificationBuilder.TYPE_ESTABLISHED; @@ -68,11 +68,9 @@ public class GroupJoiningActionProcessor extends GroupActionProcessor { webRtcInteractor.setCallInProgressNotification(TYPE_ESTABLISHED, currentState.getCallInfoState().getCallRecipient(), true); webRtcInteractor.startAudioCommunication(); - if (currentState.getLocalDeviceState().getCameraState().isEnabled()) { - webRtcInteractor.updatePhoneState(LockManager.PhoneState.IN_VIDEO); - } else { - webRtcInteractor.updatePhoneState(WebRtcUtil.getInCallPhoneState(context)); - } + boolean localVideoEnabled = currentState.getLocalDeviceState().getCameraState().isEnabled(); + boolean remoteVideoEnabled = currentState.getCallInfoState().getRemoteCallParticipantsMap().values().stream().anyMatch(CallParticipant::isVideoEnabled); + webRtcInteractor.updatePhoneState(WebRtcUtil.getInCallPhoneState(context, localVideoEnabled, remoteVideoEnabled)); try { groupCall.setOutgoingVideoMuted(!currentState.getLocalDeviceState().getCameraState().isEnabled()); diff --git a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/WebRtcUtil.java b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/WebRtcUtil.java index 0de17f8207..fb10fd9b0a 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/WebRtcUtil.java +++ b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/WebRtcUtil.java @@ -41,6 +41,18 @@ public final class WebRtcUtil { } } + /** + * Returns the appropriate phone state for an in-call scenario, considering both local and remote video state. + * If either local or remote video is enabled, returns {@link LockManager.PhoneState#IN_VIDEO} to keep the screen on. + * Otherwise, falls back to audio-device based phone state. + */ + public static @NonNull LockManager.PhoneState getInCallPhoneState(@NonNull Context context, boolean localVideoEnabled, boolean remoteVideoEnabled) { + if (localVideoEnabled || remoteVideoEnabled) { + return LockManager.PhoneState.IN_VIDEO; + } + return getInCallPhoneState(context); + } + public static @NonNull CallManager.CallMediaType getCallMediaTypeFromOfferType(@NonNull OfferMessage.Type offerType) { return offerType == OfferMessage.Type.VIDEO_CALL ? CallManager.CallMediaType.VIDEO_CALL : CallManager.CallMediaType.AUDIO_CALL; }