Add new state transitions for group call disposition.
This commit is contained in:
parent
ffce7213b4
commit
62b142cdeb
6 changed files with 237 additions and 10 deletions
|
@ -214,6 +214,175 @@ class CallTableTest {
|
|||
assertEquals(CallTable.Event.JOINED, acceptedCall?.event)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun givenAnOutgoingRingCall_whenIAcceptedOutgoingGroupCall_thenIExpectOutgoingRing() {
|
||||
val callId = 1L
|
||||
SignalDatabase.calls.insertAcceptedGroupCall(
|
||||
callId = callId,
|
||||
recipientId = groupRecipientId,
|
||||
direction = CallTable.Direction.OUTGOING,
|
||||
timestamp = 1
|
||||
)
|
||||
|
||||
val call = SignalDatabase.calls.getCallById(callId, groupRecipientId)
|
||||
assertNotNull(call)
|
||||
assertEquals(CallTable.Event.OUTGOING_RING, call?.event)
|
||||
|
||||
SignalDatabase.calls.acceptOutgoingGroupCall(
|
||||
call!!
|
||||
)
|
||||
|
||||
val acceptedCall = SignalDatabase.calls.getCallById(callId, groupRecipientId)
|
||||
assertEquals(CallTable.Event.OUTGOING_RING, acceptedCall?.event)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun givenARingingCall_whenIAcceptedOutgoingGroupCall_thenIExpectAccepted() {
|
||||
val callId = 1L
|
||||
SignalDatabase.calls.insertOrUpdateGroupCallFromRingState(
|
||||
ringId = callId,
|
||||
groupRecipientId = groupRecipientId,
|
||||
ringerRecipient = harness.others[1],
|
||||
dateReceived = System.currentTimeMillis(),
|
||||
ringState = CallManager.RingUpdate.REQUESTED
|
||||
)
|
||||
|
||||
val call = SignalDatabase.calls.getCallById(callId, groupRecipientId)
|
||||
assertNotNull(call)
|
||||
assertEquals(CallTable.Event.RINGING, call?.event)
|
||||
|
||||
SignalDatabase.calls.acceptOutgoingGroupCall(
|
||||
call!!
|
||||
)
|
||||
|
||||
val acceptedCall = SignalDatabase.calls.getCallById(callId, groupRecipientId)
|
||||
assertEquals(CallTable.Event.ACCEPTED, acceptedCall?.event)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun givenAMissedCall_whenIAcceptedOutgoingGroupCall_thenIExpectAccepted() {
|
||||
val callId = 1L
|
||||
SignalDatabase.calls.insertOrUpdateGroupCallFromRingState(
|
||||
ringId = callId,
|
||||
groupRecipientId = groupRecipientId,
|
||||
ringerRecipient = harness.others[1],
|
||||
dateReceived = System.currentTimeMillis(),
|
||||
ringState = CallManager.RingUpdate.EXPIRED_REQUEST
|
||||
)
|
||||
|
||||
val call = SignalDatabase.calls.getCallById(callId, groupRecipientId)
|
||||
assertNotNull(call)
|
||||
assertEquals(CallTable.Event.MISSED, call?.event)
|
||||
|
||||
SignalDatabase.calls.acceptOutgoingGroupCall(
|
||||
call!!
|
||||
)
|
||||
|
||||
val acceptedCall = SignalDatabase.calls.getCallById(callId, groupRecipientId)
|
||||
assertEquals(CallTable.Event.ACCEPTED, acceptedCall?.event)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun givenADeclinedCall_whenIAcceptedOutgoingGroupCall_thenIExpectAccepted() {
|
||||
val callId = 1L
|
||||
SignalDatabase.calls.insertOrUpdateGroupCallFromRingState(
|
||||
ringId = callId,
|
||||
groupRecipientId = groupRecipientId,
|
||||
ringerRecipient = harness.others[1],
|
||||
dateReceived = System.currentTimeMillis(),
|
||||
ringState = CallManager.RingUpdate.DECLINED_ON_ANOTHER_DEVICE
|
||||
)
|
||||
|
||||
val call = SignalDatabase.calls.getCallById(callId, groupRecipientId)
|
||||
assertNotNull(call)
|
||||
assertEquals(CallTable.Event.DECLINED, call?.event)
|
||||
|
||||
SignalDatabase.calls.acceptOutgoingGroupCall(
|
||||
call!!
|
||||
)
|
||||
|
||||
val acceptedCall = SignalDatabase.calls.getCallById(callId, groupRecipientId)
|
||||
assertEquals(CallTable.Event.ACCEPTED, acceptedCall?.event)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun givenAnAcceptedCall_whenIAcceptedOutgoingGroupCall_thenIExpectAccepted() {
|
||||
val callId = 1L
|
||||
SignalDatabase.calls.insertOrUpdateGroupCallFromRingState(
|
||||
ringId = callId,
|
||||
groupRecipientId = groupRecipientId,
|
||||
ringerRecipient = harness.others[1],
|
||||
dateReceived = System.currentTimeMillis(),
|
||||
ringState = CallManager.RingUpdate.REQUESTED
|
||||
)
|
||||
|
||||
val call = SignalDatabase.calls.getCallById(callId, groupRecipientId)
|
||||
assertNotNull(call)
|
||||
assertEquals(CallTable.Event.RINGING, call?.event)
|
||||
|
||||
SignalDatabase.calls.acceptIncomingGroupCall(
|
||||
call!!
|
||||
)
|
||||
|
||||
SignalDatabase.calls.acceptOutgoingGroupCall(
|
||||
SignalDatabase.calls.getCallById(callId, groupRecipientId)!!
|
||||
)
|
||||
|
||||
val acceptedCall = SignalDatabase.calls.getCallById(callId, groupRecipientId)
|
||||
assertEquals(CallTable.Event.ACCEPTED, acceptedCall?.event)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun givenAGenericGroupCall_whenIAcceptedOutgoingGroupCall_thenIExpectOutgoingRing() {
|
||||
val era = "aaa"
|
||||
val callId = CallId.fromEra(era).longValue()
|
||||
SignalDatabase.calls.insertOrUpdateGroupCallFromLocalEvent(
|
||||
groupRecipientId = groupRecipientId,
|
||||
sender = harness.others[1],
|
||||
timestamp = System.currentTimeMillis(),
|
||||
peekGroupCallEraId = "aaa",
|
||||
peekJoinedUuids = emptyList(),
|
||||
isCallFull = false
|
||||
)
|
||||
|
||||
val call = SignalDatabase.calls.getCallById(callId, groupRecipientId)
|
||||
assertNotNull(call)
|
||||
assertEquals(CallTable.Event.GENERIC_GROUP_CALL, call?.event)
|
||||
|
||||
SignalDatabase.calls.acceptOutgoingGroupCall(
|
||||
call!!
|
||||
)
|
||||
|
||||
val acceptedCall = SignalDatabase.calls.getCallById(callId, groupRecipientId)
|
||||
assertEquals(CallTable.Event.OUTGOING_RING, acceptedCall?.event)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun givenAJoinedGroupCall_whenIAcceptedOutgoingGroupCall_thenIExpectOutgoingRing() {
|
||||
val era = "aaa"
|
||||
val callId = CallId.fromEra(era).longValue()
|
||||
SignalDatabase.calls.insertOrUpdateGroupCallFromLocalEvent(
|
||||
groupRecipientId = groupRecipientId,
|
||||
sender = harness.others[1],
|
||||
timestamp = System.currentTimeMillis(),
|
||||
peekGroupCallEraId = "aaa",
|
||||
peekJoinedUuids = emptyList(),
|
||||
isCallFull = false
|
||||
)
|
||||
|
||||
val call = SignalDatabase.calls.getCallById(callId, groupRecipientId)
|
||||
assertNotNull(call)
|
||||
assertEquals(CallTable.Event.GENERIC_GROUP_CALL, call?.event)
|
||||
|
||||
SignalDatabase.calls.acceptIncomingGroupCall(
|
||||
call!!
|
||||
)
|
||||
|
||||
SignalDatabase.calls.acceptOutgoingGroupCall(SignalDatabase.calls.getCallById(callId, groupRecipientId)!!)
|
||||
val acceptedCall = SignalDatabase.calls.getCallById(callId, groupRecipientId)
|
||||
assertEquals(CallTable.Event.OUTGOING_RING, acceptedCall?.event)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun givenNoPriorCallEvent_whenIReceiveAGroupCallUpdateMessage_thenIExpectAGenericGroupCall() {
|
||||
val era = "aaa"
|
||||
|
|
|
@ -346,13 +346,12 @@ class CallTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTabl
|
|||
|
||||
fun acceptIncomingGroupCall(call: Call) {
|
||||
checkIsGroupOrAdHocCall(call)
|
||||
check(call.direction == Direction.INCOMING)
|
||||
|
||||
val newEvent = when (call.event) {
|
||||
Event.RINGING, Event.MISSED, Event.DECLINED -> Event.ACCEPTED
|
||||
Event.GENERIC_GROUP_CALL -> Event.JOINED
|
||||
else -> {
|
||||
Log.d(TAG, "Call in state ${call.event} cannot be transitioned by ACCEPTED")
|
||||
Log.d(TAG, "[acceptIncomingGroupCall] Call in state ${call.event} cannot be transitioned by ACCEPTED")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
@ -364,7 +363,32 @@ class CallTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTabl
|
|||
|
||||
ApplicationDependencies.getMessageNotifier().updateNotification(context)
|
||||
ApplicationDependencies.getDatabaseObserver().notifyCallUpdateObservers()
|
||||
Log.d(TAG, "Transitioned group call ${call.callId} from ${call.event} to $newEvent")
|
||||
Log.d(TAG, "[acceptIncomingGroupCall] Transitioned group call ${call.callId} from ${call.event} to $newEvent")
|
||||
}
|
||||
|
||||
fun acceptOutgoingGroupCall(call: Call) {
|
||||
checkIsGroupOrAdHocCall(call)
|
||||
|
||||
val newEvent = when (call.event) {
|
||||
Event.GENERIC_GROUP_CALL, Event.JOINED -> Event.OUTGOING_RING
|
||||
Event.RINGING, Event.MISSED, Event.DECLINED, Event.ACCEPTED -> {
|
||||
Log.w(TAG, "[acceptOutgoingGroupCall] This shouldn't have been an outgoing ring because the call already existed!")
|
||||
Event.ACCEPTED
|
||||
}
|
||||
else -> {
|
||||
Log.d(TAG, "[acceptOutgoingGroupCall] Call in state ${call.event} cannot be transitioned by ACCEPTED")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
writableDatabase
|
||||
.update(TABLE_NAME)
|
||||
.values(EVENT to Event.serialize(newEvent), DIRECTION to Direction.serialize(Direction.OUTGOING))
|
||||
.run()
|
||||
|
||||
ApplicationDependencies.getMessageNotifier().updateNotification(context)
|
||||
ApplicationDependencies.getDatabaseObserver().notifyCallUpdateObservers()
|
||||
Log.d(TAG, "[acceptOutgoingGroupCall] Transitioned group call ${call.callId} from ${call.event} to $newEvent")
|
||||
}
|
||||
|
||||
fun declineIncomingGroupCall(call: Call) {
|
||||
|
@ -372,7 +396,8 @@ class CallTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTabl
|
|||
check(call.direction == Direction.INCOMING)
|
||||
|
||||
val newEvent = when (call.event) {
|
||||
Event.RINGING, Event.MISSED -> Event.DECLINED
|
||||
Event.GENERIC_GROUP_CALL, Event.RINGING, Event.MISSED -> Event.DECLINED
|
||||
Event.JOINED -> Event.ACCEPTED
|
||||
else -> {
|
||||
Log.d(TAG, "Call in state ${call.event} cannot be transitioned by DECLINED")
|
||||
return
|
||||
|
@ -709,12 +734,24 @@ class CallTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTabl
|
|||
RingUpdate.EXPIRED_REQUEST, RingUpdate.CANCELLED_BY_RINGER -> {
|
||||
when (call.event) {
|
||||
Event.GENERIC_GROUP_CALL, Event.RINGING -> updateEventFromRingState(ringId, Event.MISSED, ringerRecipient)
|
||||
Event.JOINED -> updateEventFromRingState(ringId, Event.ACCEPTED, ringerRecipient)
|
||||
Event.OUTGOING_RING -> Log.w(TAG, "Received an expiration or cancellation while in OUTGOING_RING state. Ignoring.")
|
||||
else -> Unit
|
||||
}
|
||||
}
|
||||
|
||||
RingUpdate.BUSY_LOCALLY, RingUpdate.BUSY_ON_ANOTHER_DEVICE -> {
|
||||
RingUpdate.BUSY_LOCALLY -> {
|
||||
when (call.event) {
|
||||
Event.JOINED -> updateEventFromRingState(ringId, Event.ACCEPTED)
|
||||
Event.GENERIC_GROUP_CALL, Event.RINGING -> updateEventFromRingState(ringId, Event.MISSED)
|
||||
else -> {
|
||||
updateEventFromRingState(ringId, call.event, ringerRecipient)
|
||||
Log.w(TAG, "Received a busy event we can't process. Updating ringer only.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RingUpdate.BUSY_ON_ANOTHER_DEVICE -> {
|
||||
when (call.event) {
|
||||
Event.JOINED -> updateEventFromRingState(ringId, Event.ACCEPTED)
|
||||
Event.GENERIC_GROUP_CALL, Event.RINGING -> updateEventFromRingState(ringId, Event.MISSED)
|
||||
|
@ -728,7 +765,8 @@ class CallTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTabl
|
|||
|
||||
RingUpdate.DECLINED_ON_ANOTHER_DEVICE -> {
|
||||
when (call.event) {
|
||||
Event.RINGING, Event.MISSED -> updateEventFromRingState(ringId, Event.DECLINED)
|
||||
Event.RINGING, Event.MISSED, Event.GENERIC_GROUP_CALL -> updateEventFromRingState(ringId, Event.DECLINED)
|
||||
Event.JOINED -> updateEventFromRingState(ringId, Event.ACCEPTED)
|
||||
Event.OUTGOING_RING -> Log.w(TAG, "Received DECLINED_ON_ANOTHER_DEVICE while in OUTGOING_RING state.")
|
||||
else -> Unit
|
||||
}
|
||||
|
|
|
@ -1317,10 +1317,10 @@ object SyncMessageProcessor {
|
|||
if (call.timestamp > timestamp) {
|
||||
SignalDatabase.calls.setTimestamp(call.callId, recipient.id, timestamp)
|
||||
}
|
||||
if (callEvent.direction == SyncMessage.CallEvent.Direction.INCOMING) {
|
||||
if (direction == CallTable.Direction.INCOMING) {
|
||||
SignalDatabase.calls.acceptIncomingGroupCall(call)
|
||||
} else {
|
||||
warn(envelopeTimestamp, "Invalid direction OUTGOING for event ACCEPTED")
|
||||
SignalDatabase.calls.acceptOutgoingGroupCall(call)
|
||||
}
|
||||
}
|
||||
CallTable.Event.NOT_ACCEPTED -> {
|
||||
|
|
|
@ -256,7 +256,11 @@ public final class IncomingGroupCallActionProcessor extends DeviceAwareActionPro
|
|||
Log.w(TAG, "Error while trying to cancel ring " + ringId, e);
|
||||
}
|
||||
|
||||
webRtcInteractor.sendGroupCallMessage(currentState.getCallInfoState().getCallRecipient(), null, new CallId(ringId), true, false);
|
||||
CallId callId = new CallId(ringId);
|
||||
RemotePeer remotePeer = new RemotePeer(recipient.getId(), callId);
|
||||
|
||||
webRtcInteractor.sendGroupCallNotAcceptedCallEventSyncMessage(remotePeer, false);
|
||||
webRtcInteractor.sendGroupCallMessage(currentState.getCallInfoState().getCallRecipient(), null, callId, true, false);
|
||||
webRtcInteractor.updatePhoneState(LockManager.PhoneState.PROCESSING);
|
||||
webRtcInteractor.stopAudio(false);
|
||||
webRtcInteractor.updatePhoneState(LockManager.PhoneState.IDLE);
|
||||
|
|
|
@ -64,7 +64,6 @@ import org.thoughtcrime.securesms.service.webrtc.links.SignalCallLinkManager;
|
|||
import org.thoughtcrime.securesms.service.webrtc.state.WebRtcEphemeralState;
|
||||
import org.thoughtcrime.securesms.service.webrtc.state.WebRtcServiceState;
|
||||
import org.thoughtcrime.securesms.util.AppForegroundObserver;
|
||||
import org.thoughtcrime.securesms.util.BubbleUtil;
|
||||
import org.thoughtcrime.securesms.util.FeatureFlags;
|
||||
import org.thoughtcrime.securesms.util.RecipientAccessList;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
|
@ -1135,6 +1134,19 @@ public final class SignalCallManager implements CallManager.Observer, GroupCall.
|
|||
}
|
||||
}
|
||||
|
||||
public void sendGroupCallNotAcceptedCallEventSyncMessage(@NonNull RemotePeer remotePeer, boolean isOutgoing) {
|
||||
if (TextSecurePreferences.isMultiDevice(context)) {
|
||||
networkExecutor.execute(() -> {
|
||||
try {
|
||||
SyncMessage.CallEvent callEvent = CallEventSyncMessageUtil.createNotAcceptedSyncMessage(remotePeer, System.currentTimeMillis(), isOutgoing, true);
|
||||
ApplicationDependencies.getSignalServiceMessageSender().sendSyncMessage(SignalServiceSyncMessage.forCallEvent(callEvent), Optional.empty());
|
||||
} catch (IOException | UntrustedIdentityException e) {
|
||||
Log.w(TAG, "Unable to send call event sync message for " + remotePeer.getCallId().longValue(), e);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public @NonNull SignalCallLinkManager getCallLinkManager() {
|
||||
return new SignalCallLinkManager(Objects.requireNonNull(callManager));
|
||||
}
|
||||
|
|
|
@ -204,4 +204,8 @@ public class WebRtcInteractor {
|
|||
public void sendNotAcceptedCallEventSyncMessage(@NonNull RemotePeer remotePeer, boolean isOutgoing, boolean isVideoCall) {
|
||||
signalCallManager.sendNotAcceptedCallEventSyncMessage(remotePeer, isOutgoing, isVideoCall);
|
||||
}
|
||||
|
||||
public void sendGroupCallNotAcceptedCallEventSyncMessage(@NonNull RemotePeer remotePeer, boolean isOutgoing) {
|
||||
signalCallManager.sendGroupCallNotAcceptedCallEventSyncMessage(remotePeer, isOutgoing);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue