Add denial dialogs for call links.

This commit is contained in:
Alex Hart 2023-08-09 11:47:50 -03:00
parent 38bddec4ba
commit ca210f2b6d
7 changed files with 84 additions and 2 deletions

View file

@ -81,6 +81,7 @@ import org.thoughtcrime.securesms.recipients.LiveRecipient;
import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId; import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.safety.SafetyNumberBottomSheet; import org.thoughtcrime.securesms.safety.SafetyNumberBottomSheet;
import org.thoughtcrime.securesms.service.webrtc.CallLinkDisconnectReason;
import org.thoughtcrime.securesms.service.webrtc.SignalCallManager; import org.thoughtcrime.securesms.service.webrtc.SignalCallManager;
import org.thoughtcrime.securesms.sms.MessageSender; import org.thoughtcrime.securesms.sms.MessageSender;
import org.thoughtcrime.securesms.util.BottomSheetUtil; import org.thoughtcrime.securesms.util.BottomSheetUtil;
@ -145,6 +146,7 @@ public class WebRtcCallActivity extends BaseActivity implements SafetyNumberChan
private ThrottledDebouncer requestNewSizesThrottle; private ThrottledDebouncer requestNewSizesThrottle;
private PictureInPictureParams.Builder pipBuilderParams; private PictureInPictureParams.Builder pipBuilderParams;
private LifecycleDisposable lifecycleDisposable; private LifecycleDisposable lifecycleDisposable;
private long lastCallLinkDisconnectDialogShowTime;
private Disposable ephemeralStateDisposable = Disposable.empty(); private Disposable ephemeralStateDisposable = Disposable.empty();
@ -842,6 +844,18 @@ public class WebRtcCallActivity extends BaseActivity implements SafetyNumberChan
handleUntrustedIdentity(event); break; handleUntrustedIdentity(event); break;
} }
if (event.getCallLinkDisconnectReason() != null && event.getCallLinkDisconnectReason().getPostedAt() > lastCallLinkDisconnectDialogShowTime) {
lastCallLinkDisconnectDialogShowTime = System.currentTimeMillis();
if (event.getCallLinkDisconnectReason() instanceof CallLinkDisconnectReason.RemovedFromCall) {
displayRemovedFromCallLinkDialog();
} else if (event.getCallLinkDisconnectReason() instanceof CallLinkDisconnectReason.DeniedRequestToJoinCall) {
displayDeniedRequestToJoinCallLinkDialog();
} else {
throw new AssertionError("Unexpected reason: " + event.getCallLinkDisconnectReason());
}
}
boolean enableVideo = event.getLocalParticipant().getCameraState().getCameraCount() > 0 && enableVideoIfAvailable; boolean enableVideo = event.getLocalParticipant().getCameraState().getCameraCount() > 0 && enableVideoIfAvailable;
viewModel.updateFromWebRtcViewModel(event, enableVideo); viewModel.updateFromWebRtcViewModel(event, enableVideo);
@ -863,6 +877,22 @@ public class WebRtcCallActivity extends BaseActivity implements SafetyNumberChan
} }
} }
private void displayRemovedFromCallLinkDialog() {
new MaterialAlertDialogBuilder(this)
.setTitle(R.string.WebRtcCallActivity__removed_from_call)
.setMessage(R.string.WebRtcCallActivity__someone_has_removed_you_from_the_call)
.setPositiveButton(android.R.string.ok, null)
.show();
}
private void displayDeniedRequestToJoinCallLinkDialog() {
new MaterialAlertDialogBuilder(this)
.setTitle(R.string.WebRtcCallActivity__join_request_denied)
.setMessage(R.string.WebRtcCallActivity__your_request_to_join_this_call_has_been_denied)
.setPositiveButton(android.R.string.ok, null)
.show();
}
private void handleCallPreJoin(@NonNull WebRtcViewModel event) { private void handleCallPreJoin(@NonNull WebRtcViewModel event) {
if (event.getGroupState().isNotIdle()) { if (event.getGroupState().isNotIdle()) {
callScreen.setStatusFromGroupCallState(event.getGroupState()); callScreen.setStatusFromGroupCallState(event.getGroupState());

View file

@ -5,6 +5,7 @@ import org.thoughtcrime.securesms.components.webrtc.BroadcastVideoSink
import org.thoughtcrime.securesms.events.CallParticipant.Companion.createLocal import org.thoughtcrime.securesms.events.CallParticipant.Companion.createLocal
import org.thoughtcrime.securesms.recipients.Recipient import org.thoughtcrime.securesms.recipients.Recipient
import org.thoughtcrime.securesms.recipients.RecipientId import org.thoughtcrime.securesms.recipients.RecipientId
import org.thoughtcrime.securesms.service.webrtc.CallLinkDisconnectReason
import org.thoughtcrime.securesms.service.webrtc.PendingParticipantCollection import org.thoughtcrime.securesms.service.webrtc.PendingParticipantCollection
import org.thoughtcrime.securesms.service.webrtc.state.WebRtcServiceState import org.thoughtcrime.securesms.service.webrtc.state.WebRtcServiceState
import org.thoughtcrime.securesms.webrtc.audio.SignalAudioManager import org.thoughtcrime.securesms.webrtc.audio.SignalAudioManager
@ -96,6 +97,7 @@ class WebRtcViewModel(state: WebRtcServiceState) {
val participantLimit: Long? = state.callInfoState.participantLimit val participantLimit: Long? = state.callInfoState.participantLimit
val pendingParticipants: PendingParticipantCollection = state.callInfoState.pendingParticipants val pendingParticipants: PendingParticipantCollection = state.callInfoState.pendingParticipants
val isCallLink: Boolean = state.callInfoState.callRecipient.isCallLink val isCallLink: Boolean = state.callInfoState.callRecipient.isCallLink
val callLinkDisconnectReason: CallLinkDisconnectReason? = state.callInfoState.callLinkDisconnectReason
@get:JvmName("shouldRingGroup") @get:JvmName("shouldRingGroup")
val ringGroup: Boolean = state.getCallSetupState(state.callInfoState.activePeer?.callId).ringGroup val ringGroup: Boolean = state.getCallSetupState(state.callInfoState.activePeer?.callId).ringGroup

View file

@ -0,0 +1,18 @@
/*
* Copyright 2023 Signal Messenger, LLC
* SPDX-License-Identifier: AGPL-3.0-only
*/
package org.thoughtcrime.securesms.service.webrtc
/**
* Describes why a user was not able to join a call link.
*
* Note: postedAt is kept as a long to ensure Java compatibility.
*/
sealed interface CallLinkDisconnectReason {
val postedAt: Long
data class RemovedFromCall(override val postedAt: Long = System.currentTimeMillis()) : CallLinkDisconnectReason
data class DeniedRequestToJoinCall(override val postedAt: Long = System.currentTimeMillis()) : CallLinkDisconnectReason
}

View file

@ -6,6 +6,7 @@
package org.thoughtcrime.securesms.service.webrtc package org.thoughtcrime.securesms.service.webrtc
import org.signal.core.util.logging.Log import org.signal.core.util.logging.Log
import org.signal.ringrtc.GroupCall
import org.thoughtcrime.securesms.service.webrtc.state.WebRtcServiceState import org.thoughtcrime.securesms.service.webrtc.state.WebRtcServiceState
/** /**
@ -25,4 +26,19 @@ class CallLinkJoiningActionProcessor(
return currentState return currentState
} }
override fun handleGroupCallEnded(currentState: WebRtcServiceState, groupCallHash: Int, groupCallEndReason: GroupCall.GroupCallEndReason): WebRtcServiceState {
val serviceState = super.handleGroupCallEnded(currentState, groupCallHash, groupCallEndReason)
val callLinkDisconnectReason = when (groupCallEndReason) {
GroupCall.GroupCallEndReason.DENIED_REQUEST_TO_JOIN_CALL -> CallLinkDisconnectReason.DeniedRequestToJoinCall()
GroupCall.GroupCallEndReason.REMOVED_FROM_CALL -> CallLinkDisconnectReason.RemovedFromCall()
else -> null
}
return serviceState.builder()
.changeCallInfoState()
.setCallLinkDisconnectReason(callLinkDisconnectReason)
.build()
}
} }

View file

@ -9,6 +9,7 @@ import org.thoughtcrime.securesms.events.WebRtcViewModel
import org.thoughtcrime.securesms.recipients.Recipient import org.thoughtcrime.securesms.recipients.Recipient
import org.thoughtcrime.securesms.recipients.RecipientId import org.thoughtcrime.securesms.recipients.RecipientId
import org.thoughtcrime.securesms.ringrtc.RemotePeer import org.thoughtcrime.securesms.ringrtc.RemotePeer
import org.thoughtcrime.securesms.service.webrtc.CallLinkDisconnectReason
import org.thoughtcrime.securesms.service.webrtc.PendingParticipantCollection import org.thoughtcrime.securesms.service.webrtc.PendingParticipantCollection
/** /**
@ -28,7 +29,8 @@ data class CallInfoState(
var identityChangedRecipients: MutableSet<RecipientId> = mutableSetOf(), var identityChangedRecipients: MutableSet<RecipientId> = mutableSetOf(),
var remoteDevicesCount: OptionalLong = OptionalLong.empty(), var remoteDevicesCount: OptionalLong = OptionalLong.empty(),
var participantLimit: Long? = null, var participantLimit: Long? = null,
var pendingParticipants: PendingParticipantCollection = PendingParticipantCollection() var pendingParticipants: PendingParticipantCollection = PendingParticipantCollection(),
var callLinkDisconnectReason: CallLinkDisconnectReason? = null
) { ) {
val remoteCallParticipants: List<CallParticipant> val remoteCallParticipants: List<CallParticipant>

View file

@ -18,6 +18,7 @@ import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.ringrtc.Camera; import org.thoughtcrime.securesms.ringrtc.Camera;
import org.thoughtcrime.securesms.ringrtc.CameraState; import org.thoughtcrime.securesms.ringrtc.CameraState;
import org.thoughtcrime.securesms.ringrtc.RemotePeer; import org.thoughtcrime.securesms.ringrtc.RemotePeer;
import org.thoughtcrime.securesms.service.webrtc.CallLinkDisconnectReason;
import org.thoughtcrime.securesms.service.webrtc.WebRtcActionProcessor; import org.thoughtcrime.securesms.service.webrtc.WebRtcActionProcessor;
import org.thoughtcrime.securesms.webrtc.audio.SignalAudioManager; import org.thoughtcrime.securesms.webrtc.audio.SignalAudioManager;
import org.webrtc.PeerConnection; import org.webrtc.PeerConnection;
@ -358,5 +359,10 @@ public class WebRtcServiceStateBuilder {
toBuild.setPendingParticipants(toBuild.getPendingParticipants().withDenial(participant)); toBuild.setPendingParticipants(toBuild.getPendingParticipants().withDenial(participant));
return this; return this;
} }
public @NonNull CallInfoStateBuilder setCallLinkDisconnectReason(@Nullable CallLinkDisconnectReason callLinkDisconnectReason) {
toBuild.setCallLinkDisconnectReason(callLinkDisconnectReason);
return this;
}
} }
} }

View file

@ -1761,6 +1761,14 @@
<item quantity="one">%1$d person waiting</item> <item quantity="one">%1$d person waiting</item>
<item quantity="other">%1$d people waiting</item> <item quantity="other">%1$d people waiting</item>
</plurals> </plurals>
<!-- Title of dialog displayed when a user's join request is denied for call link entry -->
<string name="WebRtcCallActivity__join_request_denied">Join request denied</string>
<!-- Message of dialog displayed when a user's join request is denied for call link entry -->
<string name="WebRtcCallActivity__your_request_to_join_this_call_has_been_denied">Your request to join this call has been denied.</string>
<!-- Title of dialog displayed when a user is removed from a call link -->
<string name="WebRtcCallActivity__removed_from_call">Removed from call</string>
<!-- Message of dialog displayed when a user is removed from a call link -->
<string name="WebRtcCallActivity__someone_has_removed_you_from_the_call">Someone has removed you from the call.</string>
<!-- WebRtcCallView --> <!-- WebRtcCallView -->