diff --git a/src/org/thoughtcrime/securesms/ApplicationContext.java b/src/org/thoughtcrime/securesms/ApplicationContext.java index 29a668776d..44531d4c4b 100644 --- a/src/org/thoughtcrime/securesms/ApplicationContext.java +++ b/src/org/thoughtcrime/securesms/ApplicationContext.java @@ -42,6 +42,7 @@ import org.thoughtcrime.securesms.crypto.ProfileKeyUtil; import org.thoughtcrime.securesms.crypto.storage.TextSecureSessionStore; import org.thoughtcrime.securesms.database.Address; import org.thoughtcrime.securesms.database.DatabaseFactory; +import org.thoughtcrime.securesms.database.GroupDatabase; import org.thoughtcrime.securesms.dependencies.AxolotlStorageModule; import org.thoughtcrime.securesms.dependencies.InjectableType; import org.thoughtcrime.securesms.dependencies.SignalCommunicationModule; @@ -305,7 +306,8 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc byte[] userPrivateKey = IdentityKeyUtil.getIdentityKeyPair(this).getPrivateKey().serialize(); LokiAPIDatabase apiDB = DatabaseFactory.getLokiAPIDatabase(this); LokiUserDatabase userDB = DatabaseFactory.getLokiUserDatabase(this); - publicChatAPI = new PublicChatAPI(userPublicKey, userPrivateKey, apiDB, userDB); + GroupDatabase groupDB = DatabaseFactory.getGroupDatabase(this); + publicChatAPI = new PublicChatAPI(userPublicKey, userPrivateKey, apiDB, userDB, groupDB); return publicChatAPI; } diff --git a/src/org/thoughtcrime/securesms/conversation/ConversationActivity.java b/src/org/thoughtcrime/securesms/conversation/ConversationActivity.java index 886d603999..b89f3eed65 100644 --- a/src/org/thoughtcrime/securesms/conversation/ConversationActivity.java +++ b/src/org/thoughtcrime/securesms/conversation/ConversationActivity.java @@ -213,6 +213,7 @@ import org.thoughtcrime.securesms.util.DateUtils; import org.thoughtcrime.securesms.util.Dialogs; import org.thoughtcrime.securesms.util.DynamicLanguage; import org.thoughtcrime.securesms.util.ExpirationUtil; +import org.thoughtcrime.securesms.util.GroupUtil; import org.thoughtcrime.securesms.util.IdentityUtil; import org.thoughtcrime.securesms.util.MediaUtil; import org.thoughtcrime.securesms.util.ServiceUtil; @@ -227,6 +228,7 @@ import org.thoughtcrime.securesms.util.views.Stub; import org.whispersystems.libsignal.InvalidMessageException; import org.whispersystems.libsignal.util.guava.Optional; import org.whispersystems.signalservice.loki.api.opengroups.PublicChat; +import org.whispersystems.signalservice.loki.api.opengroups.PublicChatAPI; import org.whispersystems.signalservice.loki.protocol.mentions.Mention; import org.whispersystems.signalservice.loki.protocol.mentions.MentionsManager; import org.whispersystems.signalservice.loki.protocol.meta.SessionMetaProtocol; @@ -458,7 +460,17 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity PublicChat publicChat = DatabaseFactory.getLokiThreadDatabase(this).getPublicChat(threadId); if (publicChat != null) { - ApplicationContext.getInstance(this).getPublicChatAPI().getChannelInfo(publicChat.getChannel(), publicChat.getServer()).success(displayName -> { + PublicChatAPI publicChatAPI = ApplicationContext.getInstance(this).getPublicChatAPI(); + publicChatAPI.getChannelInfo(publicChat.getChannel(), publicChat.getServer()).success(info -> { + String groupId = GroupUtil.getEncodedOpenGroupId(publicChat.getId().getBytes()); + + publicChatAPI.updateProfileIfNeeded( + publicChat.getChannel(), + publicChat.getServer(), + groupId, + info, + false); + runOnUiThread(ConversationActivity.this::updateSubtitleTextView); return Unit.INSTANCE; }); diff --git a/src/org/thoughtcrime/securesms/database/GroupDatabase.java b/src/org/thoughtcrime/securesms/database/GroupDatabase.java index c14aff87d5..c5bd65e903 100644 --- a/src/org/thoughtcrime/securesms/database/GroupDatabase.java +++ b/src/org/thoughtcrime/securesms/database/GroupDatabase.java @@ -6,9 +6,10 @@ import android.content.ContentValues; import android.content.Context; import android.database.Cursor; import android.graphics.Bitmap; +import android.text.TextUtils; + import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import android.text.TextUtils; import com.annimon.stream.Stream; @@ -21,6 +22,7 @@ import org.thoughtcrime.securesms.util.GroupUtil; import org.thoughtcrime.securesms.util.Util; import org.whispersystems.libsignal.util.guava.Optional; import org.whispersystems.signalservice.api.messages.SignalServiceAttachmentPointer; +import org.whispersystems.signalservice.loki.database.LokiOpenGroupDatabaseProtocol; import java.io.Closeable; import java.io.IOException; @@ -29,7 +31,7 @@ import java.util.Collections; import java.util.LinkedList; import java.util.List; -public class GroupDatabase extends Database { +public class GroupDatabase extends Database implements LokiOpenGroupDatabaseProtocol { @SuppressWarnings("unused") private static final String TAG = GroupDatabase.class.getSimpleName(); @@ -240,35 +242,37 @@ public class GroupDatabase extends Database { notifyConversationListListeners(); } - public void updateTitle(String groupId, String title) { + @Override + public void updateTitle(String groupID, String newValue) { ContentValues contentValues = new ContentValues(); - contentValues.put(TITLE, title); + contentValues.put(TITLE, newValue); databaseHelper.getWritableDatabase().update(TABLE_NAME, contentValues, GROUP_ID + " = ?", - new String[] {groupId}); + new String[] {groupID}); - Recipient recipient = Recipient.from(context, Address.fromSerialized(groupId), false); - recipient.setName(title); + Recipient recipient = Recipient.from(context, Address.fromSerialized(groupID), false); + recipient.setName(newValue); } - public void updateAvatar(String groupId, Bitmap avatar) { - updateAvatar(groupId, BitmapUtil.toByteArray(avatar)); + public void updateProfilePicture(String groupID, Bitmap newValue) { + updateProfilePicture(groupID, BitmapUtil.toByteArray(newValue)); } - public void updateAvatar(String groupId, byte[] avatar) { + @Override + public void updateProfilePicture(String groupID, byte[] newValue) { long avatarId; - if (avatar != null) avatarId = Math.abs(new SecureRandom().nextLong()); + if (newValue != null) avatarId = Math.abs(new SecureRandom().nextLong()); else avatarId = 0; ContentValues contentValues = new ContentValues(2); - contentValues.put(AVATAR, avatar); + contentValues.put(AVATAR, newValue); contentValues.put(AVATAR_ID, avatarId); databaseHelper.getWritableDatabase().update(TABLE_NAME, contentValues, GROUP_ID + " = ?", - new String[] {groupId}); + new String[] {groupID}); - Recipient.applyCached(Address.fromSerialized(groupId), recipient -> recipient.setGroupAvatarId(avatarId == 0 ? null : avatarId)); + Recipient.applyCached(Address.fromSerialized(groupID), recipient -> recipient.setGroupAvatarId(avatarId == 0 ? null : avatarId)); } public void updateMembers(String groupId, List
members) { diff --git a/src/org/thoughtcrime/securesms/database/helpers/SQLCipherOpenHelper.java b/src/org/thoughtcrime/securesms/database/helpers/SQLCipherOpenHelper.java index 82d8bf0a06..d636857163 100644 --- a/src/org/thoughtcrime/securesms/database/helpers/SQLCipherOpenHelper.java +++ b/src/org/thoughtcrime/securesms/database/helpers/SQLCipherOpenHelper.java @@ -155,6 +155,7 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper { db.execSQL(LokiAPIDatabase.getCreateSessionRequestSentTimestampTableCommand()); db.execSQL(LokiAPIDatabase.getCreateSessionRequestProcessedTimestampTableCommand()); db.execSQL(LokiAPIDatabase.getCreateOpenGroupPublicKeyTableCommand()); + db.execSQL(LokiAPIDatabase.getCreateOpenGroupProfilePictureTableCommand()); db.execSQL(LokiPreKeyBundleDatabase.getCreateTableCommand()); db.execSQL(LokiPreKeyRecordDatabase.getCreateTableCommand()); db.execSQL(LokiMessageDatabase.getCreateMessageIDTableCommand()); @@ -629,6 +630,7 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper { } if (oldVersion < lokiV15) { + db.execSQL(LokiAPIDatabase.getCreateOpenGroupProfilePictureTableCommand()); db.execSQL(SharedSenderKeysDatabase.getCreateOldClosedGroupRatchetTableCommand()); } diff --git a/src/org/thoughtcrime/securesms/dependencies/SignalCommunicationModule.java b/src/org/thoughtcrime/securesms/dependencies/SignalCommunicationModule.java index 520761b536..a7449ca58d 100644 --- a/src/org/thoughtcrime/securesms/dependencies/SignalCommunicationModule.java +++ b/src/org/thoughtcrime/securesms/dependencies/SignalCommunicationModule.java @@ -159,6 +159,7 @@ public class SignalCommunicationModule { DatabaseFactory.getLokiPreKeyBundleDatabase(context), new SessionResetImplementation(context), DatabaseFactory.getLokiUserDatabase(context), + DatabaseFactory.getGroupDatabase(context), ((ApplicationContext)context.getApplicationContext()).broadcaster); } else { this.messageSender.setMessagePipe(IncomingMessageObserver.getPipe(), IncomingMessageObserver.getUnidentifiedPipe()); diff --git a/src/org/thoughtcrime/securesms/groups/GroupManager.java b/src/org/thoughtcrime/securesms/groups/GroupManager.java index 81f6feec33..694627f629 100644 --- a/src/org/thoughtcrime/securesms/groups/GroupManager.java +++ b/src/org/thoughtcrime/securesms/groups/GroupManager.java @@ -85,7 +85,7 @@ public class GroupManager { groupDatabase.create(groupId, name, new LinkedList<>(memberAddresses), null, null, new LinkedList<>(adminAddresses)); if (!mms) { - groupDatabase.updateAvatar(groupId, avatarBytes); + groupDatabase.updateProfilePicture(groupId, avatarBytes); DatabaseFactory.getRecipientDatabase(context).setProfileSharing(groupRecipient, true); return sendGroupUpdate(context, groupId, memberAddresses, name, avatarBytes, adminAddresses); } else { @@ -125,7 +125,7 @@ public class GroupManager { memberAddresses.add(Address.fromSerialized(TextSecurePreferences.getLocalNumber(context))); groupDatabase.create(groupId, name, new LinkedList<>(memberAddresses), null, null, new LinkedList<>()); - groupDatabase.updateAvatar(groupId, avatarBytes); + groupDatabase.updateProfilePicture(groupId, avatarBytes); long threadID = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(groupRecipient, ThreadDatabase.DistributionTypes.CONVERSATION); return new GroupActionResult(groupRecipient, threadID); @@ -148,7 +148,7 @@ public class GroupManager { groupDatabase.updateMembers(groupId, new LinkedList<>(memberAddresses)); groupDatabase.updateAdmins(groupId, new LinkedList<>(adminAddresses)); groupDatabase.updateTitle(groupId, name); - groupDatabase.updateAvatar(groupId, avatarBytes); + groupDatabase.updateProfilePicture(groupId, avatarBytes); if (!GroupUtil.isMmsGroup(groupId)) { return sendGroupUpdate(context, groupId, memberAddresses, name, avatarBytes, adminAddresses); diff --git a/src/org/thoughtcrime/securesms/jobs/AvatarDownloadJob.java b/src/org/thoughtcrime/securesms/jobs/AvatarDownloadJob.java index 0b2db43157..f2b95a46f0 100644 --- a/src/org/thoughtcrime/securesms/jobs/AvatarDownloadJob.java +++ b/src/org/thoughtcrime/securesms/jobs/AvatarDownloadJob.java @@ -95,7 +95,7 @@ public class AvatarDownloadJob extends BaseJob implements InjectableType { InputStream inputStream = receiver.retrieveAttachment(pointer, attachment, MAX_AVATAR_SIZE); Bitmap avatar = BitmapUtil.createScaledBitmap(context, new AttachmentModel(attachment, key, 0, digest), 500, 500); - database.updateAvatar(groupId, avatar); + database.updateProfilePicture(groupId, avatar); inputStream.close(); } } catch (BitmapDecodingException | NonSuccessfulResponseCodeException | InvalidMessageException e) { diff --git a/src/org/thoughtcrime/securesms/loki/activities/HomeActivity.kt b/src/org/thoughtcrime/securesms/loki/activities/HomeActivity.kt index 815e45ecc3..5db0535a33 100644 --- a/src/org/thoughtcrime/securesms/loki/activities/HomeActivity.kt +++ b/src/org/thoughtcrime/securesms/loki/activities/HomeActivity.kt @@ -340,20 +340,18 @@ class HomeActivity : PassphraseRequiredActionBarActivity, ConversationClickListe val threadID = thread.threadId val recipient = thread.recipient val threadDB = DatabaseFactory.getThreadDatabase(this) - val deleteThread = object : Runnable { - - override fun run() { - 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) - ApplicationContext.getInstance(this@HomeActivity).publicChatAPI!!.leave(publicChat.channel, publicChat.server) - } - threadDB.deleteConversation(threadID) - ApplicationContext.getInstance(this@HomeActivity).messageNotifier.updateNotification(this@HomeActivity) + val deleteThread = Runnable { + 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) } + 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 diff --git a/src/org/thoughtcrime/securesms/loki/api/PublicChatManager.kt b/src/org/thoughtcrime/securesms/loki/api/PublicChatManager.kt index c632e44eaa..6b710c5ea4 100644 --- a/src/org/thoughtcrime/securesms/loki/api/PublicChatManager.kt +++ b/src/org/thoughtcrime/securesms/loki/api/PublicChatManager.kt @@ -2,6 +2,7 @@ package org.thoughtcrime.securesms.loki.api import android.content.Context import android.database.ContentObserver +import android.graphics.Bitmap import android.text.TextUtils import nl.komponents.kovenant.Promise import nl.komponents.kovenant.functional.bind @@ -10,8 +11,10 @@ import org.thoughtcrime.securesms.ApplicationContext import org.thoughtcrime.securesms.database.DatabaseContentProviders import org.thoughtcrime.securesms.database.DatabaseFactory import org.thoughtcrime.securesms.groups.GroupManager +import org.thoughtcrime.securesms.util.BitmapUtil import org.thoughtcrime.securesms.util.TextSecurePreferences import org.thoughtcrime.securesms.util.Util +import org.whispersystems.signalservice.loki.api.opengroups.PublicChatInfo import org.whispersystems.signalservice.loki.api.opengroups.PublicChat class PublicChatManager(private val context: Context) { @@ -56,7 +59,8 @@ class PublicChatManager(private val context: Context) { } public fun addChat(server: String, channel: Long): Promise