From 37cec7d44fd8dba3458da775718121b370918042 Mon Sep 17 00:00:00 2001 From: Alex Hart Date: Fri, 21 Jun 2024 11:36:07 -0300 Subject: [PATCH] Implement 1:1 call event delete syncs. --- .../securesms/database/CallTableTest.kt | 10 ++++--- .../securesms/database/CallTable.kt | 26 ++++++++++++------- .../messages/SyncMessageProcessor.kt | 16 +++++++----- 3 files changed, 33 insertions(+), 19 deletions(-) diff --git a/app/src/androidTest/java/org/thoughtcrime/securesms/database/CallTableTest.kt b/app/src/androidTest/java/org/thoughtcrime/securesms/database/CallTableTest.kt index 38c63ce8b5..b02dad66b9 100644 --- a/app/src/androidTest/java/org/thoughtcrime/securesms/database/CallTableTest.kt +++ b/app/src/androidTest/java/org/thoughtcrime/securesms/database/CallTableTest.kt @@ -56,7 +56,7 @@ class CallTableTest { ) val call = SignalDatabase.calls.getCallById(callId, groupRecipientId) - SignalDatabase.calls.deleteGroupCall(call!!) + SignalDatabase.calls.markCallDeletedFromSyncEvent(call!!) val deletedCall = SignalDatabase.calls.getCallById(callId, groupRecipientId) val oldestDeletionTimestamp = SignalDatabase.calls.getOldestDeletionTimestamp() @@ -69,9 +69,10 @@ class CallTableTest { @Test fun givenNoPreExistingEvent_whenIDeleteGroupCall_thenIInsertAndMarkCallDeleted() { val callId = 1L - SignalDatabase.calls.insertDeletedGroupCallFromSyncEvent( + SignalDatabase.calls.insertDeletedCallFromSyncEvent( callId, groupRecipientId, + CallTable.Type.GROUP_CALL, CallTable.Direction.OUTGOING, System.currentTimeMillis() ) @@ -438,11 +439,12 @@ class CallTableTest { @Test fun givenADeletedCallEvent_whenIReceiveARingUpdate_thenIIgnoreTheRingUpdate() { val callId = 1L - SignalDatabase.calls.insertDeletedGroupCallFromSyncEvent( + SignalDatabase.calls.insertDeletedCallFromSyncEvent( callId = callId, recipientId = groupRecipientId, direction = CallTable.Direction.INCOMING, - timestamp = System.currentTimeMillis() + timestamp = System.currentTimeMillis(), + type = CallTable.Type.GROUP_CALL ) SignalDatabase.calls.insertOrUpdateGroupCallFromRingState( diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/CallTable.kt b/app/src/main/java/org/thoughtcrime/securesms/database/CallTable.kt index 61469cd24c..866c13e7f3 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/CallTable.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/CallTable.kt @@ -368,10 +368,12 @@ class CallTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTabl AppDependencies.databaseObserver.notifyCallUpdateObservers() } - // region Group / Ad-Hoc Calling - fun deleteGroupCall(call: Call) { - checkIsGroupOrAdHocCall(call) - + /** + * Marks the given call event DELETED. This deletes the associated message, but + * keeps the call event around for several hours to ensure out of order messages + * do not bring it back. + */ + fun markCallDeletedFromSyncEvent(call: Call) { val filter: SqlUtil.Query = getCallSelectionQuery(call.callId, call.peer) writableDatabase.withinTransaction { db -> @@ -391,18 +393,21 @@ class CallTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTabl AppDependencies.messageNotifier.updateNotification(context) AppDependencies.databaseObserver.notifyCallUpdateObservers() - Log.d(TAG, "Marked group call event for deletion: ${call.callId}") + Log.d(TAG, "Marked call event for deletion: ${call.callId}") } - fun insertDeletedGroupCallFromSyncEvent( + /** + * Inserts a call event in the DELETED state with the corresponding data. + * Deleted calls are kept around for several hours to ensure they don't reappear + * due to out of order messages. + */ + fun insertDeletedCallFromSyncEvent( callId: Long, recipientId: RecipientId, + type: Type, direction: Direction, timestamp: Long ) { - val recipient = Recipient.resolved(recipientId) - val type = if (recipient.isCallLink) Type.AD_HOC_CALL else Type.GROUP_CALL - writableDatabase .insertInto(TABLE_NAME) .values( @@ -418,8 +423,11 @@ class CallTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTabl .run(SQLiteDatabase.CONFLICT_ABORT) AppDependencies.deletedCallEventManager.scheduleIfNecessary() + Log.d(TAG, "Inserted deleted call event: $callId, $type, $direction, $timestamp") } + // region Group / Ad-Hoc Calling + fun acceptIncomingGroupCall(call: Call) { checkIsGroupOrAdHocCall(call) diff --git a/app/src/main/java/org/thoughtcrime/securesms/messages/SyncMessageProcessor.kt b/app/src/main/java/org/thoughtcrime/securesms/messages/SyncMessageProcessor.kt index 9adeb32471..6a518b5967 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/messages/SyncMessageProcessor.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/messages/SyncMessageProcessor.kt @@ -1354,16 +1354,20 @@ object SyncMessageProcessor { val call = SignalDatabase.calls.getCallById(callId, recipientId) if (call != null) { - val typeMismatch = call.type !== type - val directionMismatch = call.direction !== direction - val eventDowngrade = call.event === CallTable.Event.ACCEPTED && event !== CallTable.Event.ACCEPTED + val typeMismatch = call.type != type + val directionMismatch = call.direction != direction + val eventDowngrade = call.event == CallTable.Event.ACCEPTED && event != CallTable.Event.ACCEPTED && event != CallTable.Event.DELETE val peerMismatch = call.peer != recipientId - if (typeMismatch || directionMismatch || eventDowngrade || peerMismatch) { + if (typeMismatch || directionMismatch || peerMismatch || eventDowngrade) { warn(envelopeTimestamp, "Call event sync message is not valid for existing call record, ignoring. type: $type direction: $direction event: $event peerMismatch: $peerMismatch") + } else if (event == CallTable.Event.DELETE) { + SignalDatabase.calls.markCallDeletedFromSyncEvent(call) } else { SignalDatabase.calls.updateOneToOneCall(callId, event) } + } else if (event == CallTable.Event.DELETE) { + SignalDatabase.calls.insertDeletedCallFromSyncEvent(callId, recipientId, type, direction, timestamp) } else { SignalDatabase.calls.insertOneToOneCall(callId, timestamp, recipientId, type, direction, event) } @@ -1432,7 +1436,7 @@ object SyncMessageProcessor { return } when (event) { - CallTable.Event.DELETE -> SignalDatabase.calls.deleteGroupCall(call) + CallTable.Event.DELETE -> SignalDatabase.calls.markCallDeletedFromSyncEvent(call) CallTable.Event.ACCEPTED -> { if (call.timestamp > timestamp) { SignalDatabase.calls.setTimestamp(call.callId, recipient.id, timestamp) @@ -1457,7 +1461,7 @@ object SyncMessageProcessor { } } else { when (event) { - CallTable.Event.DELETE -> SignalDatabase.calls.insertDeletedGroupCallFromSyncEvent(callEvent.id!!, recipient.id, direction, timestamp) + CallTable.Event.DELETE -> SignalDatabase.calls.insertDeletedCallFromSyncEvent(callEvent.id!!, recipient.id, type, direction, timestamp) CallTable.Event.ACCEPTED -> SignalDatabase.calls.insertAcceptedGroupCall(callEvent.id!!, recipient.id, direction, timestamp) CallTable.Event.NOT_ACCEPTED -> { if (callEvent.direction == SyncMessage.CallEvent.Direction.INCOMING) {