From cff01021c2bd00933327cfb4441646377476d1c1 Mon Sep 17 00:00:00 2001 From: Alex Hart Date: Tue, 13 Jun 2023 16:42:55 -0300 Subject: [PATCH] Ensure call links only ever have one call event associated with them. --- .../securesms/calls/log/CallLogAdapter.kt | 2 + .../securesms/database/CallTable.kt | 65 ++++++++++++++++--- 2 files changed, 58 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/calls/log/CallLogAdapter.kt b/app/src/main/java/org/thoughtcrime/securesms/calls/log/CallLogAdapter.kt index 97dfbc5939..5eaaffdaef 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/calls/log/CallLogAdapter.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/calls/log/CallLogAdapter.kt @@ -353,6 +353,7 @@ class CallLogAdapter( MessageTypes.INCOMING_AUDIO_CALL_TYPE, MessageTypes.INCOMING_VIDEO_CALL_TYPE -> R.drawable.symbol_arrow_downleft_compact_16 MessageTypes.OUTGOING_AUDIO_CALL_TYPE, MessageTypes.OUTGOING_VIDEO_CALL_TYPE -> R.drawable.symbol_arrow_upright_compact_16 MessageTypes.GROUP_CALL_TYPE -> when { + call.type == CallTable.Type.AD_HOC_CALL -> R.drawable.symbol_link_compact_16 call.event == CallTable.Event.MISSED -> R.drawable.symbol_missed_incoming_24 call.event == CallTable.Event.GENERIC_GROUP_CALL || call.event == CallTable.Event.JOINED -> R.drawable.symbol_group_compact_16 call.direction == CallTable.Direction.INCOMING -> R.drawable.symbol_arrow_downleft_compact_16 @@ -374,6 +375,7 @@ class CallLogAdapter( MessageTypes.OUTGOING_AUDIO_CALL_TYPE -> R.string.CallLogAdapter__outgoing MessageTypes.OUTGOING_VIDEO_CALL_TYPE -> R.string.CallLogAdapter__outgoing MessageTypes.GROUP_CALL_TYPE -> when { + call.type == CallTable.Type.AD_HOC_CALL -> R.string.CallLogAdapter__call_link call.event == CallTable.Event.MISSED -> R.string.CallLogAdapter__missed call.event == CallTable.Event.GENERIC_GROUP_CALL || call.event == CallTable.Event.JOINED -> R.string.CallPreference__group_call call.direction == CallTable.Direction.INCOMING -> R.string.CallLogAdapter__incoming 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 51e03148dd..34348b2a04 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/CallTable.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/CallTable.kt @@ -428,6 +428,23 @@ class CallTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTabl peekJoinedUuids: Collection, isCallFull: Boolean ) { + val recipient = Recipient.resolved(groupRecipientId) + if (recipient.isCallLink) { + handleCallLinkUpdate(recipient, timestamp, peekGroupCallEraId) + } else { + handleGroupUpdate(recipient, sender, timestamp, peekGroupCallEraId, peekJoinedUuids, isCallFull) + } + } + + private fun handleGroupUpdate( + groupRecipient: Recipient, + sender: RecipientId, + timestamp: Long, + peekGroupCallEraId: String?, + peekJoinedUuids: Collection, + isCallFull: Boolean + ) { + check(groupRecipient.isPushV2Group) writableDatabase.withinTransaction { if (peekGroupCallEraId.isNullOrEmpty()) { Log.w(TAG, "Dropping local call event with null era id.") @@ -435,7 +452,7 @@ class CallTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTabl } val callId = CallId.fromEra(peekGroupCallEraId).longValue() - val call = getCallById(callId, groupRecipientId) + val call = getCallById(callId, groupRecipient.id) val messageId: MessageId = if (call != null) { if (call.event == Event.DELETE) { Log.d(TAG, "Dropping group call update for deleted call.") @@ -460,7 +477,7 @@ class CallTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTabl ) } else { SignalDatabase.messages.insertGroupCall( - groupRecipientId, + groupRecipient.id, sender, timestamp, peekGroupCallEraId, @@ -473,12 +490,43 @@ class CallTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTabl callId, messageId, sender, - groupRecipientId, + groupRecipient.id, timestamp ) } } + private fun handleCallLinkUpdate( + callLinkRecipient: Recipient, + timestamp: Long, + peekGroupCallEraId: String? + ) { + check(callLinkRecipient.isCallLink) + + val callId = peekGroupCallEraId?.let { CallId.fromEra(it).longValue() } ?: return + + writableDatabase.withinTransaction { db -> + db.delete(TABLE_NAME) + .where("$PEER = ?", callLinkRecipient.id.serialize()) + .run() + + db.insertInto(TABLE_NAME) + .values( + CALL_ID to callId, + MESSAGE_ID to null, + PEER to callLinkRecipient.id.toLong(), + EVENT to Event.serialize(Event.GENERIC_GROUP_CALL), + TYPE to Type.serialize(Type.AD_HOC_CALL), + DIRECTION to Direction.serialize(Direction.OUTGOING), + TIMESTAMP to timestamp, + RINGER to null + ).run(SQLiteDatabase.CONFLICT_ABORT) + } + + Log.d(TAG, "Inserted new call event for call link. Call Id: $callId") + ApplicationDependencies.getDatabaseObserver().notifyCallUpdateObservers() + } + private fun insertCallEventFromGroupUpdate( callId: Long, messageId: MessageId?, @@ -691,6 +739,9 @@ class CallTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTabl ) { val direction = if (ringerRecipient == Recipient.self().id) Direction.OUTGOING else Direction.INCOMING + val recipient = Recipient.resolved(groupRecipientId) + check(recipient.isPushV2Group) + writableDatabase.withinTransaction { db -> val messageId = SignalDatabase.messages.insertGroupCall( groupRecipientId = groupRecipientId, @@ -977,7 +1028,7 @@ class CallTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTabl cte ) p INNER JOIN ${RecipientTable.TABLE_NAME} ON ${RecipientTable.TABLE_NAME}.${RecipientTable.ID} = $PEER - INNER JOIN ${MessageTable.TABLE_NAME} ON ${MessageTable.TABLE_NAME}.${MessageTable.ID} = $MESSAGE_ID + LEFT JOIN ${MessageTable.TABLE_NAME} ON ${MessageTable.TABLE_NAME}.${MessageTable.ID} = $MESSAGE_ID LEFT JOIN ${GroupTable.TABLE_NAME} ON ${GroupTable.TABLE_NAME}.${GroupTable.RECIPIENT_ID} = ${RecipientTable.TABLE_NAME}.${RecipientTable.ID} WHERE true_parent = p.$ID ${if (queryClause.where.isNotEmpty()) "AND ${queryClause.where}" else ""} ORDER BY p.$TIMESTAMP DESC @@ -1050,14 +1101,10 @@ class CallTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTabl companion object Deserializer : Serializer { fun getMessageType(type: Type, direction: Direction, event: Event): Long { - if (type == Type.GROUP_CALL) { + if (type == Type.GROUP_CALL || type == Type.AD_HOC_CALL) { return MessageTypes.GROUP_CALL_TYPE } - if (type == Type.AD_HOC_CALL) { - error("Ad-Hoc calls are not linked to messages.") - } - return if (direction == Direction.INCOMING && event == Event.MISSED) { if (type == Type.VIDEO_CALL) MessageTypes.MISSED_VIDEO_CALL_TYPE else MessageTypes.MISSED_AUDIO_CALL_TYPE } else if (direction == Direction.INCOMING) {