From c741e32824504d71a0164b339a0a3b6652fc7728 Mon Sep 17 00:00:00 2001 From: Cody Henthorne Date: Fri, 10 Feb 2023 13:08:51 -0500 Subject: [PATCH] Fix stale thread id when a conversation is deleted. --- .../conversation/ConversationFragment.java | 51 ++++++++----------- .../securesms/database/DatabaseObserver.java | 22 ++++++++ .../securesms/database/ThreadTable.kt | 3 ++ 3 files changed, 45 insertions(+), 31 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationFragment.java b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationFragment.java index 9f6e8b8fdd..4b1212d458 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationFragment.java +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationFragment.java @@ -109,6 +109,7 @@ import org.thoughtcrime.securesms.conversation.mutiselect.forward.MultiselectFor import org.thoughtcrime.securesms.conversation.mutiselect.forward.MultiselectForwardFragmentArgs; import org.thoughtcrime.securesms.conversation.quotes.MessageQuotesBottomSheet; import org.thoughtcrime.securesms.conversation.ui.error.EnableCallNotificationSettingsDialog; +import org.thoughtcrime.securesms.database.DatabaseObserver; import org.thoughtcrime.securesms.database.MessageTable; import org.thoughtcrime.securesms.database.SignalDatabase; import org.thoughtcrime.securesms.database.model.InMemoryMessageRecord; @@ -264,6 +265,8 @@ public class ConversationFragment extends LoggingFragment implements Multiselect private @Nullable ConversationData conversationData; private @Nullable ChatWallpaper chatWallpaper; + private final DatabaseObserver.Observer threadDeletedObserver = this::onThreadDelete; + public static void prepare(@NonNull Context context) { FrameLayout parent = new FrameLayout(context); parent.setLayoutParams(new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.WRAP_CONTENT)); @@ -526,26 +529,6 @@ public class ConversationFragment extends LoggingFragment implements Multiselect updateToolbarDependentMargins(); } - public void onNewIntent() { - Log.d(TAG, "[onNewIntent]"); - - if (actionMode != null) { - actionMode.finish(); - } - - long oldThreadId = threadId; - - initializeResources(); - messageRequestViewModel.setConversationInfo(recipient.getId(), threadId); - - int startingPosition = getStartPosition(); - if (startingPosition != -1 && oldThreadId == threadId) { - list.post(() -> moveToPosition(startingPosition, () -> Log.w(TAG, "Could not scroll to requested message."))); - } else { - initializeListAdapter(); - } - } - public void moveToLastSeen() { int lastSeenPosition = conversationData != null ? conversationData.getLastSeenPosition() : 0; if (lastSeenPosition <= 0) { @@ -697,8 +680,8 @@ public class ConversationFragment extends LoggingFragment implements Multiselect long oldThreadId = threadId; int startingPosition = getStartPosition(); - this.recipient = Recipient.live(conversationViewModel.getArgs().getRecipientId()); - this.threadId = conversationViewModel.getArgs().getThreadId(); + this.recipient = Recipient.live(conversationViewModel.getArgs().getRecipientId()); + setThreadId(conversationViewModel.getArgs().getThreadId()); this.markReadHelper = new MarkReadHelper(ConversationId.forConversation(threadId), requireContext(), getViewLifecycleOwner()); conversationViewModel.onConversationDataAvailable(recipient.getId(), threadId, startingPosition); @@ -718,6 +701,12 @@ public class ConversationFragment extends LoggingFragment implements Multiselect } } + private void setThreadId(long threadId) { + this.threadId = threadId; + ApplicationDependencies.getDatabaseObserver().unregisterObserver(threadDeletedObserver); + ApplicationDependencies.getDatabaseObserver().registerConversationDeleteObserver(this.threadId, threadDeletedObserver); + } + private void initializeListAdapter() { if (this.recipient != null) { if (getListAdapter() != null && getListAdapter().isForRecipientId(this.recipient.getId())) { @@ -945,7 +934,7 @@ public class ConversationFragment extends LoggingFragment implements Multiselect if (this.threadId != threadId) { Log.i(TAG, "ThreadId changed from " + this.threadId + " to " + threadId + ". Recipient was " + this.recipient.getId() + " and is now " + recipient.getId()); - this.threadId = threadId; + setThreadId(threadId); messageRequestViewModel.setConversationInfo(recipient.getId(), threadId); snapToTopDataObserver.requestScrollPosition(0); @@ -1060,14 +1049,7 @@ public class ConversationFragment extends LoggingFragment implements Multiselect @Override protected Void doInBackground(Void... voids) { for (MessageRecord messageRecord : messageRecords) { - boolean threadDeleted = SignalDatabase.messages().deleteMessage(messageRecord.getId()); - - if (threadDeleted) { - threadId = -1; - conversationViewModel.clearThreadId(); - messageCountsViewModel.clearThreadId(); - listener.setThreadId(threadId); - } + SignalDatabase.messages().deleteMessage(messageRecord.getId()); } return null; @@ -1085,6 +1067,13 @@ public class ConversationFragment extends LoggingFragment implements Multiselect return builder; } + private void onThreadDelete() { + setThreadId(-1); + conversationViewModel.clearThreadId(); + messageCountsViewModel.clearThreadId(); + listener.setThreadId(threadId); + } + private static boolean isNoteToSelfDelete(Set messageRecords) { return messageRecords.stream().allMatch(messageRecord -> messageRecord.isOutgoing() && messageRecord.getRecipient().isSelf()); } diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/DatabaseObserver.java b/app/src/main/java/org/thoughtcrime/securesms/database/DatabaseObserver.java index 832112e7a3..be666ad982 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/DatabaseObserver.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/DatabaseObserver.java @@ -43,6 +43,7 @@ public class DatabaseObserver { private static final String KEY_RECIPIENT = "Recipient"; private static final String KEY_STORY_OBSERVER = "Story"; private static final String KEY_SCHEDULED_MESSAGES = "ScheduledMessages"; + private static final String KEY_CONVERSATION_DELETES = "ConversationDeletes"; private final Application application; private final Executor executor; @@ -50,6 +51,7 @@ public class DatabaseObserver { private final Set conversationListObservers; private final Map> conversationObservers; private final Map> verboseConversationObservers; + private final Map> conversationDeleteObservers; private final Map> paymentObservers; private final Map> scheduledMessageObservers; private final Set allPaymentsObservers; @@ -68,6 +70,7 @@ public class DatabaseObserver { this.conversationListObservers = new HashSet<>(); this.conversationObservers = new HashMap<>(); this.verboseConversationObservers = new HashMap<>(); + this.conversationDeleteObservers = new HashMap<>(); this.paymentObservers = new HashMap<>(); this.allPaymentsObservers = new HashSet<>(); this.chatColorsObservers = new HashSet<>(); @@ -99,6 +102,12 @@ public class DatabaseObserver { }); } + public void registerConversationDeleteObserver(long threadId, @NonNull Observer listener) { + executor.execute(() -> { + registerMapped(conversationDeleteObservers, threadId, listener); + }); + } + public void registerPaymentObserver(@NonNull UUID paymentId, @NonNull Observer listener) { executor.execute(() -> { registerMapped(paymentObservers, paymentId, listener); @@ -181,6 +190,7 @@ public class DatabaseObserver { notificationProfileObservers.remove(listener); unregisterMapped(storyObservers, listener); unregisterMapped(scheduledMessageObservers, listener); + unregisterMapped(conversationDeleteObservers, listener); }); } @@ -212,6 +222,18 @@ public class DatabaseObserver { } } + public void notifyConversationDeleteListeners(Set threadIds) { + for (long threadId : threadIds) { + notifyConversationDeleteListeners(threadId); + } + } + + public void notifyConversationDeleteListeners(long threadId) { + runPostSuccessfulTransaction(KEY_CONVERSATION_DELETES + threadId, () -> { + notifyMapped(conversationDeleteObservers, threadId); + }); + } + public void notifyConversationListListeners() { runPostSuccessfulTransaction(KEY_CONVERSATION_LIST, () -> { for (Observer listener : conversationListObservers) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/ThreadTable.kt b/app/src/main/java/org/thoughtcrime/securesms/database/ThreadTable.kt index 484efd9381..814d5ba922 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/ThreadTable.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/ThreadTable.kt @@ -43,6 +43,7 @@ import org.thoughtcrime.securesms.database.model.MmsMessageRecord import org.thoughtcrime.securesms.database.model.ThreadRecord import org.thoughtcrime.securesms.database.model.databaseprotos.BodyRangeList import org.thoughtcrime.securesms.database.model.serialize +import org.thoughtcrime.securesms.dependencies.ApplicationDependencies import org.thoughtcrime.securesms.groups.BadGroupIdException import org.thoughtcrime.securesms.groups.GroupId import org.thoughtcrime.securesms.jobs.OptimizeMessageSearchIndexJob @@ -1040,6 +1041,7 @@ class ThreadTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa notifyConversationListListeners() notifyConversationListeners(threadId) + ApplicationDependencies.getDatabaseObserver().notifyConversationDeleteListeners(threadId) ConversationUtil.clearShortcuts(context, setOf(recipientIdForThreadId)) } @@ -1056,6 +1058,7 @@ class ThreadTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa notifyConversationListListeners() notifyConversationListeners(selectedConversations) + ApplicationDependencies.getDatabaseObserver().notifyConversationDeleteListeners(selectedConversations) ConversationUtil.clearShortcuts(context, recipientIdsForThreadIds) }