Thread deletion cleanup.

This commit is contained in:
Anton Chekulaev 2020-11-23 16:59:44 +11:00
parent 4307140e5c
commit 0ebb382edd
3 changed files with 50 additions and 60 deletions

View File

@ -3,6 +3,7 @@ package org.thoughtcrime.securesms.groups;
import android.content.Context;
import android.graphics.Bitmap;
import android.net.Uri;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@ -23,7 +24,6 @@ import org.thoughtcrime.securesms.util.BitmapUtil;
import org.thoughtcrime.securesms.util.GroupUtil;
import org.thoughtcrime.securesms.util.MediaUtil;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.whispersystems.libsignal.util.guava.Optional;
import org.whispersystems.signalservice.api.util.InvalidNumberException;
import org.whispersystems.signalservice.internal.push.SignalServiceProtos.GroupContext;
@ -134,8 +134,8 @@ public class GroupManager {
return new GroupActionResult(groupRecipient, threadID);
}
public static boolean deleteGroup(@NonNull String groupId,
@NonNull Context context)
public static boolean deleteGroup(@NonNull String groupId,
@NonNull Context context)
{
final GroupDatabase groupDatabase = DatabaseFactory.getGroupDatabase(context);
final ThreadDatabase threadDatabase = DatabaseFactory.getThreadDatabase(context);

View File

@ -9,7 +9,6 @@ import android.database.Cursor
import android.net.Uri
import android.os.AsyncTask
import android.os.Bundle
import android.os.Handler
import android.text.Spannable
import android.text.SpannableString
import android.text.style.ForegroundColorSpan
@ -18,11 +17,15 @@ import android.view.View
import android.widget.RelativeLayout
import android.widget.Toast
import androidx.lifecycle.Observer
import androidx.lifecycle.lifecycleScope
import androidx.loader.app.LoaderManager
import androidx.loader.content.Loader
import androidx.localbroadcastmanager.content.LocalBroadcastManager
import androidx.recyclerview.widget.LinearLayoutManager
import kotlinx.android.synthetic.main.activity_home.*
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import network.loki.messenger.R
import org.thoughtcrime.securesms.ApplicationContext
import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity
@ -71,24 +74,6 @@ class HomeActivity : PassphraseRequiredActionBarActivity, ConversationClickListe
override fun onCreate(savedInstanceState: Bundle?, isReady: Boolean) {
super.onCreate(savedInstanceState, isReady)
// Process any outstanding deletes
val threadDatabase = DatabaseFactory.getThreadDatabase(this)
val archivedConversationCount = threadDatabase.archivedConversationListCount
if (archivedConversationCount > 0) {
val archivedConversations = threadDatabase.archivedConversationList
archivedConversations.moveToFirst()
fun deleteThreadAtCurrentPosition() {
val threadID = archivedConversations.getLong(archivedConversations.getColumnIndex(ThreadDatabase.ID))
AsyncTask.execute {
threadDatabase.deleteConversation(threadID)
(applicationContext as ApplicationContext).messageNotifier.updateNotification(this)
}
}
deleteThreadAtCurrentPosition()
while (archivedConversations.moveToNext()) {
deleteThreadAtCurrentPosition()
}
}
// Double check that the long poller is up
(applicationContext as ApplicationContext).startPollingIfNeeded()
// Set content view
@ -341,58 +326,56 @@ class HomeActivity : PassphraseRequiredActionBarActivity, ConversationClickListe
val threadID = thread.threadId
val recipient = thread.recipient
val threadDB = DatabaseFactory.getThreadDatabase(this)
val deleteThread = Runnable {
//TODO Move open group related logic to OpenGroupUtilities / PublicChatManager / GroupManager
AsyncTask.execute {
val publicChat = DatabaseFactory.getLokiThreadDatabase(this@HomeActivity).getPublicChat(threadID)
if (publicChat != null) {
val apiDB = DatabaseFactory.getLokiAPIDatabase(this@HomeActivity)
apiDB.removeLastMessageServerID(publicChat.channel, publicChat.server)
apiDB.removeLastDeletionServerID(publicChat.channel, publicChat.server)
apiDB.clearOpenGroupProfilePictureURL(publicChat.channel, publicChat.server)
ApplicationContext.getInstance(this@HomeActivity).publicChatAPI!!.leave(publicChat.channel, publicChat.server)
//FIXME Group deletion should be synchronized with the related thread deletion.
val groupId = threadDB.getRecipientForThreadId(threadID)!!.address.serialize()
GroupManager.deleteGroup(groupId, this@HomeActivity)
}
threadDB.deleteConversation(threadID)
ApplicationContext.getInstance(this@HomeActivity).messageNotifier.updateNotification(this@HomeActivity)
}
}
val dialogMessage = if (recipient.isGroupRecipient) R.string.activity_home_leave_group_dialog_message else R.string.activity_home_delete_conversation_dialog_message
val dialog = AlertDialog.Builder(this)
dialog.setMessage(dialogMessage)
dialog.setPositiveButton(R.string.yes) { _, _ ->
dialog.setPositiveButton(R.string.yes) { _, _ -> lifecycleScope.launch(Dispatchers.Main) {
val context = this@HomeActivity as Context
val isClosedGroup = recipient.address.isClosedGroup
// Send a leave group message if this is an active closed group
if (isClosedGroup && DatabaseFactory.getGroupDatabase(this).isActive(recipient.address.toGroupString())) {
if (isClosedGroup && DatabaseFactory.getGroupDatabase(context).isActive(recipient.address.toGroupString())) {
var isSSKBasedClosedGroup: Boolean
var groupPublicKey: String?
try {
groupPublicKey = ClosedGroupsProtocol.doubleDecodeGroupID(recipient.address.toString()).toHexString()
isSSKBasedClosedGroup = DatabaseFactory.getSSKDatabase(this).isSSKBasedClosedGroup(groupPublicKey)
isSSKBasedClosedGroup = DatabaseFactory.getSSKDatabase(context).isSSKBasedClosedGroup(groupPublicKey)
} catch (e: IOException) {
groupPublicKey = null
isSSKBasedClosedGroup = false
}
if (isSSKBasedClosedGroup) {
ClosedGroupsProtocol.leave(this, groupPublicKey!!)
} else if (!ClosedGroupsProtocol.leaveLegacyGroup(this, recipient)) {
Toast.makeText(this, R.string.activity_home_leaving_group_failed_message, Toast.LENGTH_LONG).show()
return@setPositiveButton
ClosedGroupsProtocol.leave(context, groupPublicKey!!)
} else if (!ClosedGroupsProtocol.leaveLegacyGroup(context, recipient)) {
Toast.makeText(context, R.string.activity_home_leaving_group_failed_message, Toast.LENGTH_LONG).show()
return@launch
}
}
// Archive the conversation and then delete it after 10 seconds (the case where the
// app was closed before the conversation could be deleted is handled in onCreate)
threadDB.archiveConversation(threadID)
val delay = if (isClosedGroup) 10000L else 1000L
val handler = Handler()
handler.postDelayed(deleteThread, delay)
withContext(Dispatchers.IO) {
val publicChat = DatabaseFactory.getLokiThreadDatabase(context).getPublicChat(threadID)
//TODO Move open group related logic to OpenGroupUtilities / PublicChatManager / GroupManager
if (publicChat != null) {
val apiDB = DatabaseFactory.getLokiAPIDatabase(context)
apiDB.removeLastMessageServerID(publicChat.channel, publicChat.server)
apiDB.removeLastDeletionServerID(publicChat.channel, publicChat.server)
apiDB.clearOpenGroupProfilePictureURL(publicChat.channel, publicChat.server)
ApplicationContext.getInstance(context).publicChatAPI!!
.leave(publicChat.channel, publicChat.server)
ApplicationContext.getInstance(context).publicChatManager
.removeChat(publicChat.server, publicChat.channel)
} else {
threadDB.deleteConversation(threadID)
}
ApplicationContext.getInstance(context).messageNotifier.updateNotification(context)
}
// Notify the user
val toastMessage = if (recipient.isGroupRecipient) R.string.MessageRecord_left_group else R.string.activity_home_conversation_deleted_message
Toast.makeText(this, toastMessage, Toast.LENGTH_LONG).show()
}
Toast.makeText(context, toastMessage, Toast.LENGTH_LONG).show()
}}
dialog.setNegativeButton(R.string.no) { _, _ ->
// Do nothing
}

View File

@ -5,9 +5,6 @@ import android.database.ContentObserver
import android.graphics.Bitmap
import android.text.TextUtils
import androidx.annotation.WorkerThread
import nl.komponents.kovenant.Promise
import nl.komponents.kovenant.functional.bind
import nl.komponents.kovenant.functional.map
import org.thoughtcrime.securesms.ApplicationContext
import org.thoughtcrime.securesms.database.DatabaseContentProviders
import org.thoughtcrime.securesms.database.DatabaseFactory
@ -96,11 +93,21 @@ class PublicChatManager(private val context: Context) {
ApplicationContext.getInstance(context).publicChatAPI?.setDisplayName(displayName, server)
}
// Start polling
Util.runOnMain{ startPollersIfNeeded() }
Util.runOnMain { startPollersIfNeeded() }
return chat
}
public fun removeChat(server: String, channel: Long) {
val threadDB = DatabaseFactory.getThreadDatabase(context)
val groupId = PublicChat.getId(channel, server)
val threadId = GroupManager.getOpenGroupThreadID(groupId, context)
val groupAddress = threadDB.getRecipientForThreadId(threadId)!!.address.serialize()
GroupManager.deleteGroup(groupAddress, context)
Util.runOnMain { startPollersIfNeeded() }
}
private fun refreshChatsAndPollers() {
val chatsInDB = DatabaseFactory.getLokiThreadDatabase(context).getAllPublicChats()
val removedChatThreadIds = chats.keys.filter { !chatsInDB.keys.contains(it) }