Fix call log multiselect deletions.

This commit is contained in:
Alex Hart
2023-04-25 16:42:33 -03:00
committed by GitHub
parent eb9915d445
commit 0e631508b2
7 changed files with 106 additions and 28 deletions

View File

@@ -51,10 +51,11 @@ class CallLogRepository : CallLogPagedDataSource.CallRepository {
}
fun deleteAllCallLogsExcept(
selectedCallRowIds: Set<Long>
selectedCallRowIds: Set<Long>,
missedOnly: Boolean
): Completable {
return Completable.fromAction {
SignalDatabase.calls.deleteAllCallEventsExcept(selectedCallRowIds)
SignalDatabase.calls.deleteAllCallEventsExcept(selectedCallRowIds, missedOnly)
}.observeOn(Schedulers.io())
}
}

View File

@@ -6,6 +6,7 @@ import androidx.annotation.MainThread
* Encapsulates a single deletion action
*/
class CallLogStagedDeletion(
private val filter: CallLogFilter,
private val stateSnapshot: CallLogSelectionState,
private val repository: CallLogRepository
) {
@@ -35,7 +36,7 @@ class CallLogStagedDeletion(
.toSet()
if (stateSnapshot.isExclusionary()) {
repository.deleteAllCallLogsExcept(callRowIds).subscribe()
repository.deleteAllCallLogsExcept(callRowIds, filter == CallLogFilter.MISSED).subscribe()
} else {
repository.deleteSelectedCallLogs(callRowIds).subscribe()
}

View File

@@ -101,6 +101,7 @@ class CallLogViewModel(
callLogStore.update {
it.copy(
stagedDeletion = CallLogStagedDeletion(
it.filter,
CallLogSelectionState.empty().toggle(call.id),
callLogRepository
)
@@ -114,6 +115,7 @@ class CallLogViewModel(
callLogStore.update {
it.copy(
stagedDeletion = CallLogStagedDeletion(
it.filter,
it.selectionState,
callLogRepository
)

View File

@@ -20,6 +20,7 @@ import org.signal.core.util.requireNonNullString
import org.signal.core.util.requireObject
import org.signal.core.util.requireString
import org.signal.core.util.select
import org.signal.core.util.toSingleLine
import org.signal.core.util.update
import org.signal.core.util.withinTransaction
import org.signal.ringrtc.CallId
@@ -544,6 +545,7 @@ class CallTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTabl
else -> Log.w(TAG, "Received a REQUESTED ring event while in ${call.event}. Ignoring.")
}
}
RingUpdate.EXPIRED_REQUEST, RingUpdate.CANCELLED_BY_RINGER -> {
when (call.event) {
Event.GENERIC_GROUP_CALL, Event.RINGING -> updateEventFromRingState(ringId, Event.MISSED, ringerRecipient)
@@ -551,6 +553,7 @@ class CallTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTabl
else -> Unit
}
}
RingUpdate.BUSY_LOCALLY, RingUpdate.BUSY_ON_ANOTHER_DEVICE -> {
when (call.event) {
Event.JOINED -> updateEventFromRingState(ringId, Event.ACCEPTED)
@@ -558,9 +561,11 @@ class CallTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTabl
else -> Log.w(TAG, "Received a busy event we can't process. Ignoring.")
}
}
RingUpdate.ACCEPTED_ON_ANOTHER_DEVICE -> {
updateEventFromRingState(ringId, Event.ACCEPTED)
}
RingUpdate.DECLINED_ON_ANOTHER_DEVICE -> {
when (call.event) {
Event.RINGING, Event.MISSED -> updateEventFromRingState(ringId, Event.DECLINED)
@@ -577,14 +582,17 @@ class CallTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTabl
Log.w(TAG, "Missed original ring request for $ringId")
Event.ACCEPTED
}
RingUpdate.DECLINED_ON_ANOTHER_DEVICE -> {
Log.w(TAG, "Missed original ring request for $ringId")
Event.DECLINED
}
RingUpdate.BUSY_LOCALLY, RingUpdate.BUSY_ON_ANOTHER_DEVICE -> {
Log.w(TAG, "Missed original ring request for $ringId")
Event.MISSED
}
RingUpdate.CANCELLED_BY_RINGER -> {
Log.w(TAG, "Missed original ring request for $ringId")
Event.MISSED
@@ -702,10 +710,72 @@ class CallTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTabl
updateCallEventDeletionTimestamps()
}
fun deleteAllCallEventsExcept(callRowIds: Set<Long>) {
val messageIds = getMessageIds(callRowIds)
SignalDatabase.messages.deleteAllCallUpdatesExcept(messageIds)
updateCallEventDeletionTimestamps()
fun deleteAllCallEventsExcept(callRowIds: Set<Long>, missedOnly: Boolean) {
val callFilter = if (missedOnly) {
"$EVENT = ${Event.serialize(Event.MISSED)} AND $DELETION_TIMESTAMP = 0"
} else {
"$DELETION_TIMESTAMP = 0"
}
if (callRowIds.isEmpty()) {
val threadIds = writableDatabase.withinTransaction { db ->
val ids = db.select(MessageTable.THREAD_ID)
.from(MessageTable.TABLE_NAME)
.where(
"""
${MessageTable.ID} IN (
SELECT $MESSAGE_ID FROM $TABLE_NAME
WHERE $callFilter
)
""".toSingleLine()
)
.run()
.readToList { it.requireLong(MessageTable.THREAD_ID) }
db.delete(MessageTable.TABLE_NAME)
.where(
"""
${MessageTable.ID} IN (
SELECT $MESSAGE_ID FROM $TABLE_NAME
WHERE $callFilter
)
""".toSingleLine()
)
.run()
ids.toSet()
}
threadIds.forEach {
SignalDatabase.threads.update(
threadId = it,
unarchive = false,
allowDeletion = true
)
}
notifyConversationListeners(threadIds)
notifyConversationListListeners()
updateCallEventDeletionTimestamps()
} else {
writableDatabase.withinTransaction { db ->
SqlUtil.buildCollectionQuery(
column = ID,
values = callRowIds,
prefix = "$callFilter AND",
collectionOperator = SqlUtil.CollectionOperator.NOT_IN
).forEach { query ->
val messageIds = db.select(MESSAGE_ID)
.from(TABLE_NAME)
.where(query.where, query.whereArgs)
.run()
.readToList { it.requireLong(MESSAGE_ID) }
.toSet()
SignalDatabase.messages.deleteCallUpdates(messageIds)
updateCallEventDeletionTimestamps()
}
}
}
}
@Discouraged("Using this method is generally considered an error. Utilize other deletion methods instead of this.")
@@ -876,8 +946,6 @@ class CallTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTabl
val date = cursor.requireLong(MessageTable.DATE_RECEIVED)
val groupCallDetails = GroupCallUpdateDetailsUtil.parse(cursor.requireString(MessageTable.BODY))
Log.d(TAG, "${cursor.requireNonNullString("in_period")}")
val children = cursor.requireNonNullString("children")
.split(',')
.map { it.toLong() }

View File

@@ -3193,14 +3193,10 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
return deleteCallUpdatesInternal(messageIds, SqlUtil.CollectionOperator.IN)
}
/**
* Deletes all call updates except for those specified in the parameter.
*/
fun deleteAllCallUpdatesExcept(excludedMessageIds: Set<Long>): Int {
return deleteCallUpdatesInternal(excludedMessageIds, SqlUtil.CollectionOperator.NOT_IN)
}
private fun deleteCallUpdatesInternal(messageIds: Set<Long>, collectionOperator: SqlUtil.CollectionOperator): Int {
private fun deleteCallUpdatesInternal(
messageIds: Set<Long>,
collectionOperator: SqlUtil.CollectionOperator
): Int {
var rowsDeleted = 0
val threadIds: Set<Long> = writableDatabase.withinTransaction {
SqlUtil.buildCollectionQuery(

View File

@@ -10,6 +10,7 @@ import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint
import org.thoughtcrime.securesms.recipients.RecipientId
import org.thoughtcrime.securesms.ringrtc.RemotePeer
import org.thoughtcrime.securesms.service.webrtc.CallEventSyncMessageUtil
import org.thoughtcrime.securesms.util.FeatureFlags
import org.whispersystems.signalservice.api.messages.multidevice.SignalServiceSyncMessage
import java.util.Optional
import java.util.concurrent.TimeUnit
@@ -46,8 +47,7 @@ class CallSyncEventJob private constructor(
)
}
@JvmStatic
fun createForDelete(conversationRecipientId: RecipientId, callId: Long, isIncoming: Boolean): CallSyncEventJob {
private fun createForDelete(conversationRecipientId: RecipientId, callId: Long, isIncoming: Boolean): CallSyncEventJob {
return CallSyncEventJob(
getParameters(conversationRecipientId),
conversationRecipientId,
@@ -57,16 +57,17 @@ class CallSyncEventJob private constructor(
)
}
@JvmStatic
fun enqueueDeleteSyncEvents(deletedCalls: Set<CallTable.Call>) {
for (call in deletedCalls) {
ApplicationDependencies.getJobManager().add(
createForDelete(
call.peer,
call.callId,
call.direction == CallTable.Direction.INCOMING
if (FeatureFlags.callDeleteSync()) {
for (call in deletedCalls) {
ApplicationDependencies.getJobManager().add(
createForDelete(
call.peer,
call.callId,
call.direction == CallTable.Direction.INCOMING
)
)
)
}
}
}

View File

@@ -111,6 +111,7 @@ public final class FeatureFlags {
private static final String AD_HOC_CALLING = "android.calling.ad.hoc";
private static final String EDIT_MESSAGE_RECEIVE = "android.editMessage.receive";
private static final String EDIT_MESSAGE_SEND = "android.editMessage.send";
private static final String CALL_DELETE_SYNC = "android.calling.deleteSync";
/**
* We will only store remote values for flags in this set. If you want a flag to be controllable
@@ -177,7 +178,8 @@ public final class FeatureFlags {
@VisibleForTesting
static final Set<String> NOT_REMOTE_CAPABLE = SetUtil.newHashSet(
PHONE_NUMBER_PRIVACY,
AD_HOC_CALLING
AD_HOC_CALLING,
CALL_DELETE_SYNC
);
/**
@@ -626,6 +628,13 @@ public final class FeatureFlags {
return getBoolean(AD_HOC_CALLING, false);
}
/**
* Whether sending deletion sync events is supported
*/
public static boolean callDeleteSync() {
return getBoolean(CALL_DELETE_SYNC, false);
}
/** Only for rendering debug info. */
public static synchronized @NonNull Map<String, Object> getMemoryValues() {
return new TreeMap<>(REMOTE_VALUES);