mirror of
https://github.com/signalapp/Signal-Android.git
synced 2025-12-24 13:08:46 +00:00
Fix call log multiselect deletions.
This commit is contained in:
@@ -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())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
@@ -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
|
||||
)
|
||||
|
||||
@@ -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() }
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user