diff --git a/app/src/main/java/org/session/libsession/messaging/messages/signal/IncomingMediaMessage.kt b/app/src/main/java/org/session/libsession/messaging/messages/signal/IncomingMediaMessage.kt index 4c9a9482a9..adf9331452 100644 --- a/app/src/main/java/org/session/libsession/messaging/messages/signal/IncomingMediaMessage.kt +++ b/app/src/main/java/org/session/libsession/messaging/messages/signal/IncomingMediaMessage.kt @@ -1,7 +1,6 @@ package org.session.libsession.messaging.messages.signal -import network.loki.messenger.libsession_util.protocol.ProMessageFeature -import network.loki.messenger.libsession_util.util.BitSet +import network.loki.messenger.libsession_util.protocol.ProFeature import org.session.libsession.messaging.messages.visible.VisibleMessage import org.session.libsession.messaging.sending_receiving.attachments.Attachment import org.session.libsession.messaging.sending_receiving.data_extraction.DataExtractionNotificationInfoMessage @@ -20,7 +19,7 @@ class IncomingMediaMessage( val body: String?, val group: Address.GroupLike?, val attachments: List, - val proFeatures: BitSet, + val proFeatures: Set, val messageContent: MessageContent?, val quote: QuoteModel?, val linkPreviews: List, diff --git a/app/src/main/java/org/session/libsession/messaging/messages/signal/IncomingTextMessage.kt b/app/src/main/java/org/session/libsession/messaging/messages/signal/IncomingTextMessage.kt index ac619f5f89..3d3be4641e 100644 --- a/app/src/main/java/org/session/libsession/messaging/messages/signal/IncomingTextMessage.kt +++ b/app/src/main/java/org/session/libsession/messaging/messages/signal/IncomingTextMessage.kt @@ -1,7 +1,6 @@ package org.session.libsession.messaging.messages.signal -import network.loki.messenger.libsession_util.protocol.ProMessageFeature -import network.loki.messenger.libsession_util.util.BitSet +import network.loki.messenger.libsession_util.protocol.ProFeature import org.session.libsession.messaging.calls.CallMessageType import org.session.libsession.messaging.messages.visible.OpenGroupInvitation import org.session.libsession.messaging.messages.visible.VisibleMessage @@ -21,7 +20,7 @@ data class IncomingTextMessage( val hasMention: Boolean, val isOpenGroupInvitation: Boolean, val isSecureMessage: Boolean, - val proFeatures: BitSet, + val proFeatures: Set, val isGroupMessage: Boolean = false, val isGroupUpdateMessage: Boolean = false, ) { @@ -34,8 +33,6 @@ data class IncomingTextMessage( CallMessageType.CALL_FIRST_MISSED, ) - val proFeaturesRawValue: Long get() = proFeatures.rawValue - init { check(!isGroupUpdateMessage || isGroupMessage) { "A message cannot be a group update message if it is not a group message" @@ -81,7 +78,7 @@ data class IncomingTextMessage( hasMention = false, isOpenGroupInvitation = false, isSecureMessage = false, - proFeatures = BitSet(), + proFeatures = emptySet(), ) companion object { @@ -109,7 +106,7 @@ data class IncomingTextMessage( hasMention = false, isOpenGroupInvitation = true, isSecureMessage = false, - proFeatures = BitSet(), + proFeatures = emptySet(), ) } } diff --git a/app/src/main/java/org/session/libsession/messaging/messages/signal/OutgoingMediaMessage.kt b/app/src/main/java/org/session/libsession/messaging/messages/signal/OutgoingMediaMessage.kt index fcc138998c..b7183cd8c8 100644 --- a/app/src/main/java/org/session/libsession/messaging/messages/signal/OutgoingMediaMessage.kt +++ b/app/src/main/java/org/session/libsession/messaging/messages/signal/OutgoingMediaMessage.kt @@ -1,7 +1,6 @@ package org.session.libsession.messaging.messages.signal -import network.loki.messenger.libsession_util.protocol.ProMessageFeature -import network.loki.messenger.libsession_util.util.BitSet +import network.loki.messenger.libsession_util.protocol.ProFeature import org.session.libsession.messaging.messages.visible.VisibleMessage import org.session.libsession.messaging.sending_receiving.attachments.Attachment import org.session.libsession.messaging.sending_receiving.link_preview.LinkPreview @@ -21,7 +20,7 @@ class OutgoingMediaMessage( val linkPreviews: List, val group: Address.GroupLike?, val isGroupUpdateMessage: Boolean, - val proFeatures: BitSet = BitSet() + val proFeatures: Set = emptySet() ) { init { check(!isGroupUpdateMessage || group != null) { diff --git a/app/src/main/java/org/session/libsession/messaging/messages/signal/OutgoingTextMessage.kt b/app/src/main/java/org/session/libsession/messaging/messages/signal/OutgoingTextMessage.kt index c4cc2d847a..912da3d5c7 100644 --- a/app/src/main/java/org/session/libsession/messaging/messages/signal/OutgoingTextMessage.kt +++ b/app/src/main/java/org/session/libsession/messaging/messages/signal/OutgoingTextMessage.kt @@ -1,7 +1,6 @@ package org.session.libsession.messaging.messages.signal -import network.loki.messenger.libsession_util.protocol.ProMessageFeature -import network.loki.messenger.libsession_util.util.BitSet +import network.loki.messenger.libsession_util.protocol.ProFeature import org.session.libsession.messaging.messages.visible.OpenGroupInvitation import org.session.libsession.messaging.messages.visible.VisibleMessage import org.session.libsession.messaging.utilities.UpdateMessageData @@ -14,7 +13,7 @@ data class OutgoingTextMessage( val expireStartedAtMillis: Long, val sentTimestampMillis: Long, val isOpenGroupInvitation: Boolean, - val proFeatures: BitSet = BitSet() + val proFeatures: Set = emptySet() ) { constructor( message: VisibleMessage, @@ -30,8 +29,6 @@ data class OutgoingTextMessage( isOpenGroupInvitation = false, ) - val proFeaturesRawValue: Long get() = proFeatures.rawValue - companion object { fun fromOpenGroupInvitation( invitation: OpenGroupInvitation, diff --git a/app/src/main/java/org/session/libsession/messaging/messages/visible/VisibleMessage.kt b/app/src/main/java/org/session/libsession/messaging/messages/visible/VisibleMessage.kt index fe5d81b97e..410d244885 100644 --- a/app/src/main/java/org/session/libsession/messaging/messages/visible/VisibleMessage.kt +++ b/app/src/main/java/org/session/libsession/messaging/messages/visible/VisibleMessage.kt @@ -2,14 +2,17 @@ package org.session.libsession.messaging.messages.visible import androidx.annotation.Keep import network.loki.messenger.BuildConfig +import network.loki.messenger.libsession_util.protocol.ProFeature import network.loki.messenger.libsession_util.protocol.ProMessageFeature -import network.loki.messenger.libsession_util.util.BitSet +import network.loki.messenger.libsession_util.protocol.ProProfileFeature import org.session.libsession.database.MessageDataProvider import org.session.libsession.messaging.messages.Message import org.session.libsession.messaging.messages.copyExpiration import org.session.libsession.messaging.sending_receiving.attachments.DatabaseAttachment import org.session.libsignal.protos.SignalServiceProtos import org.session.libsignal.utilities.Log +import org.thoughtcrime.securesms.pro.toProMessageBitSetValue +import org.thoughtcrime.securesms.pro.toProProfileBitSetValue import org.session.libsession.messaging.sending_receiving.attachments.Attachment as SignalAttachment /** @@ -27,12 +30,12 @@ data class VisibleMessage( var reaction: Reaction? = null, var hasMention: Boolean = false, var blocksMessageRequests: Boolean = false, - var proFeatures: BitSet = BitSet() + var proFeatures: Set = emptySet() ) : Message() { // This empty constructor is needed for kryo serialization @Keep - constructor(): this(proFeatures = BitSet()) + constructor(): this(proFeatures = emptySet()) override val isSelfSendValid: Boolean = true @@ -114,8 +117,16 @@ data class VisibleMessage( } // Pro features - if (!proFeatures.isEmpty) { - builder.proMessageBuilder.setMsgBitset(proFeatures.rawValue) + if (proFeatures.any { it is ProMessageFeature }) { + builder.proMessageBuilder.setMsgBitset( + proFeatures.toProMessageBitSetValue() + ) + } + + if (proFeatures.any { it is ProProfileFeature }) { + builder.proMessageBuilder.setProfileBitset( + proFeatures.toProProfileBitSetValue() + ) } } // endregion diff --git a/app/src/main/java/org/session/libsession/messaging/sending_receiving/MessageParser.kt b/app/src/main/java/org/session/libsession/messaging/sending_receiving/MessageParser.kt index 1b33d234f9..9caf81ae8b 100644 --- a/app/src/main/java/org/session/libsession/messaging/sending_receiving/MessageParser.kt +++ b/app/src/main/java/org/session/libsession/messaging/sending_receiving/MessageParser.kt @@ -6,6 +6,7 @@ import network.loki.messenger.libsession_util.protocol.DecodedEnvelope import network.loki.messenger.libsession_util.protocol.DecodedPro import network.loki.messenger.libsession_util.protocol.SessionProtocol import network.loki.messenger.libsession_util.util.BitSet +import network.loki.messenger.libsession_util.util.asSequence import org.session.libsession.database.StorageProtocol import org.session.libsession.messaging.messages.Message import org.session.libsession.messaging.messages.control.CallMessage @@ -137,7 +138,10 @@ class MessageParser @Inject constructor( // Only process pro features post pro launch if (prefs.forcePostPro()) { - (message as? VisibleMessage)?.proFeatures = pro?.proMessageFeatures ?: BitSet() + (message as? VisibleMessage)?.proFeatures = buildSet { + pro?.proMessageFeatures?.asSequence()?.let(::addAll) + pro?.proProfileFeatures?.asSequence()?.let(::addAll) + } } // Validate diff --git a/app/src/main/java/org/session/libsession/messaging/sending_receiving/MessageRequestResponseHandler.kt b/app/src/main/java/org/session/libsession/messaging/sending_receiving/MessageRequestResponseHandler.kt index 1764ba1817..a1db7543b2 100644 --- a/app/src/main/java/org/session/libsession/messaging/sending_receiving/MessageRequestResponseHandler.kt +++ b/app/src/main/java/org/session/libsession/messaging/sending_receiving/MessageRequestResponseHandler.kt @@ -161,7 +161,7 @@ class MessageRequestResponseHandler @Inject constructor( body = null, group = null, attachments = emptyList(), - proFeatures = BitSet(), + proFeatures = emptySet(), messageContent = null, quote = null, linkPreviews = emptyList(), diff --git a/app/src/main/java/org/session/libsession/utilities/TextSecurePreferences.kt b/app/src/main/java/org/session/libsession/utilities/TextSecurePreferences.kt index e0d3d85c22..caa5489453 100644 --- a/app/src/main/java/org/session/libsession/utilities/TextSecurePreferences.kt +++ b/app/src/main/java/org/session/libsession/utilities/TextSecurePreferences.kt @@ -20,8 +20,10 @@ import kotlinx.coroutines.flow.update import kotlinx.serialization.json.Json import network.loki.messenger.BuildConfig import network.loki.messenger.R +import network.loki.messenger.libsession_util.protocol.ProFeature import network.loki.messenger.libsession_util.protocol.ProMessageFeature -import network.loki.messenger.libsession_util.util.BitSet +import network.loki.messenger.libsession_util.protocol.ProProfileFeature +import network.loki.messenger.libsession_util.util.toBitSet import org.session.libsession.messaging.MessagingModuleConfiguration import org.session.libsession.messaging.file_server.FileServer import org.session.libsession.utilities.TextSecurePreferences.Companion.AUTOPLAY_AUDIO_MESSAGES @@ -61,7 +63,8 @@ import org.session.libsession.utilities.TextSecurePreferences.Companion.SHOW_DON import org.session.libsession.utilities.TextSecurePreferences.Companion._events import org.session.libsignal.utilities.Log import org.thoughtcrime.securesms.debugmenu.DebugMenuViewModel -import org.thoughtcrime.securesms.pro.ProStatusManager +import org.thoughtcrime.securesms.pro.toProMessageFeatures +import org.thoughtcrime.securesms.pro.toProProfileFeatures import java.io.IOException import java.time.ZonedDateTime import java.util.Arrays @@ -216,8 +219,8 @@ interface TextSecurePreferences { fun forcedShortTTL(): Boolean fun setForcedShortTTL(value: Boolean) - fun getDebugMessageFeatures(): BitSet - fun setDebugMessageFeatures(features: BitSet) + fun getDebugMessageFeatures(): Set + fun setDebugMessageFeatures(features: Set) fun getDebugSubscriptionType(): DebugMenuViewModel.DebugSubscriptionStatus? fun setDebugSubscriptionType(status: DebugMenuViewModel.DebugSubscriptionStatus?) @@ -409,7 +412,8 @@ interface TextSecurePreferences { const val IN_APP_REVIEW_STATE = "in_app_review_state" - const val DEBUG_MESSAGE_FEATURES = "debug_message_features_long" + const val DEBUG_PRO_MESSAGE_FEATURES = "debug_pro_message_features" + const val DEBUG_PRO_PROFILE_FEATURES = "debug_pro_profile_features" const val DEBUG_SUBSCRIPTION_STATUS = "debug_subscription_status" const val DEBUG_PRO_PLAN_STATUS = "debug_pro_plan_status" const val DEBUG_FORCE_NO_BILLING = "debug_pro_has_billing" @@ -1751,12 +1755,16 @@ class AppTextSecurePreferences @Inject constructor( setStringPreference(TextSecurePreferences.DEPRECATING_START_TIME_OVERRIDE, value.toString()) } } - override fun getDebugMessageFeatures(): BitSet { - return BitSet(getLongPreference( TextSecurePreferences.DEBUG_MESSAGE_FEATURES, 0)) + override fun getDebugMessageFeatures(): Set { + return buildSet { + getLongPreference(TextSecurePreferences.DEBUG_PRO_MESSAGE_FEATURES, 0L).toProMessageFeatures(this) + getLongPreference(TextSecurePreferences.DEBUG_PRO_PROFILE_FEATURES, 0L).toProProfileFeatures(this) + } } - override fun setDebugMessageFeatures(features: BitSet) { - setLongPreference(TextSecurePreferences.DEBUG_MESSAGE_FEATURES, features.rawValue) + override fun setDebugMessageFeatures(features: Set) { + setLongPreference(TextSecurePreferences.DEBUG_PRO_MESSAGE_FEATURES, features.filterIsInstance().toBitSet().rawValue) + setLongPreference(TextSecurePreferences.DEBUG_PRO_PROFILE_FEATURES, features.filterIsInstance().toBitSet().rawValue) } override fun getDebugSubscriptionType(): DebugMenuViewModel.DebugSubscriptionStatus? { diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/MessageDetailsViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/MessageDetailsViewModel.kt index 5087e5b370..31ec45ffbf 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/MessageDetailsViewModel.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/MessageDetailsViewModel.kt @@ -203,7 +203,7 @@ class MessageDetailsViewModel @AssistedInject constructor( senderIsBlinded = IdPrefix.fromValue(sender.address.toString())?.isBlinded() ?: false, thread = conversation, readOnly = isDeprecatedLegacyGroup, - proFeatures = proStatusManager.getMessageProFeatures(messageRecord).asSequence().toSet(), + proFeatures = proStatusManager.getMessageProFeatures(messageRecord), proBadgeClickable = !recipientRepository.getSelf().isPro // no badge click if the current user is pro ) } diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/MmsDatabase.kt b/app/src/main/java/org/thoughtcrime/securesms/database/MmsDatabase.kt index 4d042c6157..730c922c66 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/MmsDatabase.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/MmsDatabase.kt @@ -19,6 +19,7 @@ package org.thoughtcrime.securesms.database import android.content.ContentValues import android.content.Context import android.database.Cursor +import androidx.sqlite.db.SupportSQLiteDatabase import com.annimon.stream.Stream import dagger.Lazy import dagger.hilt.android.qualifiers.ApplicationContext @@ -54,6 +55,10 @@ import org.thoughtcrime.securesms.database.model.content.DisappearingMessageUpda import org.thoughtcrime.securesms.database.model.content.MessageContent import org.thoughtcrime.securesms.mms.MmsException import org.thoughtcrime.securesms.mms.SlideDeck +import org.thoughtcrime.securesms.pro.toProMessageBitSetValue +import org.thoughtcrime.securesms.pro.toProMessageFeatures +import org.thoughtcrime.securesms.pro.toProProfileBitSetValue +import org.thoughtcrime.securesms.pro.toProProfileFeatures import org.thoughtcrime.securesms.util.asSequence import java.io.Closeable import java.io.IOException @@ -442,7 +447,8 @@ class MmsDatabase @Inject constructor( contentValues.put(MESSAGE_BOX, mailbox) contentValues.put(THREAD_ID, threadId) contentValues.put(STATUS, Status.DOWNLOAD_INITIALIZED) - contentValues.put(PRO_FEATURES, retrieved.proFeatures.rawValue) + contentValues.put(PRO_MESSAGE_FEATURES, retrieved.proFeatures.toProMessageBitSetValue()) + contentValues.put(PRO_PROFILE_FEATURES, retrieved.proFeatures.toProProfileBitSetValue()) // In open groups messages should be sorted by their server timestamp var receivedTimestamp = serverTimestamp if (serverTimestamp == 0L) { @@ -559,7 +565,8 @@ class MmsDatabase @Inject constructor( contentValues.put(EXPIRES_IN, message.expiresInMillis) contentValues.put(EXPIRE_STARTED, message.expireStartedAtMillis) contentValues.put(ADDRESS, message.recipient.toString()) - contentValues.put(PRO_FEATURES, message.proFeatures.rawValue) + contentValues.put(PRO_PROFILE_FEATURES, message.proFeatures.toProProfileBitSetValue()) + contentValues.put(PRO_MESSAGE_FEATURES, message.proFeatures.toProMessageBitSetValue()) contentValues.put( DELIVERY_RECEIPT_COUNT, Stream.of(earlyDeliveryReceipts.values).mapToLong { obj: Long -> obj } @@ -976,7 +983,11 @@ class MmsDatabase @Inject constructor( val expireStarted = cursor.getLong(cursor.getColumnIndexOrThrow(EXPIRE_STARTED)) val hasMention = cursor.getInt(cursor.getColumnIndexOrThrow(HAS_MENTION)) == 1 val messageContentJson = cursor.getString(cursor.getColumnIndexOrThrow(MESSAGE_CONTENT)) - val proFeatures = cursor.getLong(cursor.getColumnIndexOrThrow(PRO_FEATURES)) + + val proFeatures = buildSet { + cursor.getLong(cursor.getColumnIndexOrThrow(PRO_MESSAGE_FEATURES)).toProMessageFeatures(this) + cursor.getLong(cursor.getColumnIndexOrThrow(PRO_PROFILE_FEATURES)).toProProfileFeatures(this) + } if (!isReadReceiptsEnabled(context)) { readReceiptCount = 0 @@ -1020,7 +1031,7 @@ class MmsDatabase @Inject constructor( /* reactions = */ reactions, /* hasMention = */ hasMention, /* messageContent = */ messageContent, - /* proFeaturesRawValue = */ proFeatures + /* proFeatures = */ proFeatures ) } @@ -1221,8 +1232,9 @@ class MmsDatabase @Inject constructor( "DROP TABLE $TEMP_TABLE_NAME" ) - const val ADD_PRO_FEATURES_COLUMN = """ - ALTER TABLE $TABLE_NAME ADD COLUMN $PRO_FEATURES INTEGER NOT NULL DEFAULT 0; - """ + fun addProFeatureColumns(db: SupportSQLiteDatabase) { + db.execSQL("ALTER TABLE $TABLE_NAME ADD COLUMN $PRO_PROFILE_FEATURES INTEGER NOT NULL DEFAULT 0") + db.execSQL("ALTER TABLE $TABLE_NAME ADD COLUMN $PRO_MESSAGE_FEATURES INTEGER NOT NULL DEFAULT 0") + } } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/MmsSmsColumns.java b/app/src/main/java/org/thoughtcrime/securesms/database/MmsSmsColumns.java index 3ef4d48926..5decc3301d 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/MmsSmsColumns.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/MmsSmsColumns.java @@ -43,7 +43,8 @@ public interface MmsSmsColumns { public static final String SERVER_HASH = "server_hash"; - public static final String PRO_FEATURES = "pro_features"; + public static final String PRO_MESSAGE_FEATURES = "pro_message_features"; + public static final String PRO_PROFILE_FEATURES = "pro_profile_features"; public static class Types { protected static final long TOTAL_MASK = 0xFFFFFFFF; diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/MmsSmsDatabaseSQL.kt b/app/src/main/java/org/thoughtcrime/securesms/database/MmsSmsDatabaseSQL.kt index 7c04ff12f2..e4682ee9e6 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/MmsSmsDatabaseSQL.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/MmsSmsDatabaseSQL.kt @@ -112,7 +112,8 @@ fun buildMmsSmsCombinedQuery( NULL AS ${MmsDatabase.LINK_PREVIEWS}, ${MmsSmsColumns.HAS_MENTION}, ($smsHashQuery) AS ${MmsSmsColumns.SERVER_HASH}, - ${MmsSmsColumns.PRO_FEATURES} + ${MmsSmsColumns.PRO_MESSAGE_FEATURES}, + ${MmsSmsColumns.PRO_PROFILE_FEATURES} FROM ${SmsDatabase.TABLE_NAME} $whereStatement """ @@ -202,7 +203,8 @@ fun buildMmsSmsCombinedQuery( ${MmsDatabase.LINK_PREVIEWS}, ${MmsSmsColumns.HAS_MENTION}, ($mmsHashQuery) AS ${MmsSmsColumns.SERVER_HASH}, - ${MmsSmsColumns.PRO_FEATURES} + ${MmsSmsColumns.PRO_MESSAGE_FEATURES}, + ${MmsSmsColumns.PRO_PROFILE_FEATURES} FROM ${MmsDatabase.TABLE_NAME} $whereStatement """ diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/SmsDatabase.java b/app/src/main/java/org/thoughtcrime/securesms/database/SmsDatabase.java index 49e0117fd5..f579417396 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/SmsDatabase.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/SmsDatabase.java @@ -23,6 +23,9 @@ import android.content.Context; import android.database.Cursor; +import androidx.collection.ArraySet; +import androidx.sqlite.db.SupportSQLiteDatabase; + import com.annimon.stream.Stream; import net.zetetic.database.sqlcipher.SQLiteDatabase; @@ -43,6 +46,7 @@ import org.thoughtcrime.securesms.database.model.MessageId; import org.thoughtcrime.securesms.database.model.ReactionRecord; import org.thoughtcrime.securesms.database.model.SmsMessageRecord; +import org.thoughtcrime.securesms.pro.ProFeatureExtKt; import java.io.Closeable; import java.util.ArrayList; @@ -51,6 +55,7 @@ import java.util.LinkedList; import java.util.List; import java.util.Map; +import java.util.Set; import javax.inject.Inject; import javax.inject.Provider; @@ -58,6 +63,10 @@ import dagger.Lazy; import dagger.hilt.android.qualifiers.ApplicationContext; +import network.loki.messenger.libsession_util.protocol.ProFeature; +import network.loki.messenger.libsession_util.protocol.ProMessageFeature; +import network.loki.messenger.libsession_util.protocol.ProProfileFeature; +import network.loki.messenger.libsession_util.util.BitSet; /** * Database for storage of SMS messages. @@ -128,7 +137,10 @@ public class SmsDatabase extends MessagingDatabase { public static final String ADD_IS_DELETED_COLUMN = "ALTER TABLE " + TABLE_NAME + " ADD COLUMN " + IS_DELETED_COLUMN_DEF; public static final String ADD_IS_GROUP_UPDATE_COLUMN = "ALTER TABLE " + TABLE_NAME +" ADD COLUMN " + IS_GROUP_UPDATE +" BOOL GENERATED ALWAYS AS (" + TYPE +" & " + GROUP_UPDATE_MESSAGE_BIT +" != 0) VIRTUAL"; - public static final String ADD_PRO_FEATURES_COLUMN = "ALTER TABLE " + TABLE_NAME + " ADD COLUMN " + PRO_FEATURES + " INTEGER NOT NULL DEFAULT 0"; + public static void addProFeatureColumns(SupportSQLiteDatabase db) { + db.execSQL("ALTER TABLE " + TABLE_NAME + " ADD COLUMN " + PRO_MESSAGE_FEATURES + " INTEGER NOT NULL DEFAULT 0"); + db.execSQL("ALTER TABLE " + TABLE_NAME + " ADD COLUMN " + PRO_PROFILE_FEATURES + " INTEGER NOT NULL DEFAULT 0"); + } private static final EarlyReceiptCache earlyDeliveryReceiptCache = new EarlyReceiptCache(); private static final EarlyReceiptCache earlyReadReceiptCache = new EarlyReceiptCache(); @@ -430,7 +442,8 @@ protected Optional insertMessageInbox(IncomingTextMessage message, values.put(BODY, message.getMessage()); values.put(TYPE, type); values.put(THREAD_ID, threadId); - values.put(PRO_FEATURES, message.getProFeaturesRawValue()); + values.put(PRO_MESSAGE_FEATURES, ProFeatureExtKt.toProMessageBitSetValue(message.getProFeatures())); + values.put(PRO_PROFILE_FEATURES, ProFeatureExtKt.toProProfileBitSetValue(message.getProFeatures())); if (message.getPush() && isDuplicate(message, threadId)) { Log.w(TAG, "Duplicate message (" + message.getSentTimestampMillis() + "), ignoring..."); @@ -511,7 +524,8 @@ public long insertMessageOutbox(long threadId, OutgoingTextMessage message, contentValues.put(EXPIRE_STARTED, message.getExpireStartedAtMillis()); contentValues.put(DELIVERY_RECEIPT_COUNT, Stream.of(earlyDeliveryReceipts.values()).mapToLong(Long::longValue).sum()); contentValues.put(READ_RECEIPT_COUNT, Stream.of(earlyReadReceipts.values()).mapToLong(Long::longValue).sum()); - contentValues.put(PRO_FEATURES, message.getProFeaturesRawValue()); + contentValues.put(PRO_MESSAGE_FEATURES, ProFeatureExtKt.toProMessageBitSetValue(message.getProFeatures())); + contentValues.put(PRO_PROFILE_FEATURES, ProFeatureExtKt.toProProfileBitSetValue(message.getProFeatures())); if (isDuplicate(message, threadId)) { Log.w(TAG, "Duplicate message (" + message.getSentTimestampMillis() + "), ignoring..."); @@ -699,7 +713,10 @@ public SmsMessageRecord getCurrent() { long expireStarted = cursor.getLong(cursor.getColumnIndexOrThrow(SmsDatabase.EXPIRE_STARTED)); String body = cursor.getString(cursor.getColumnIndexOrThrow(SmsDatabase.BODY)); boolean hasMention = cursor.getInt(cursor.getColumnIndexOrThrow(SmsDatabase.HAS_MENTION)) == 1; - long proFeatures = cursor.getLong(cursor.getColumnIndexOrThrow(SmsDatabase.PRO_FEATURES)); + + final ArraySet proFeatures = new ArraySet<>(); + ProFeatureExtKt.toProMessageFeatures(cursor.getLong(cursor.getColumnIndexOrThrow(SmsDatabase.PRO_MESSAGE_FEATURES)), proFeatures); + ProFeatureExtKt.toProProfileFeatures(cursor.getLong(cursor.getColumnIndexOrThrow(SmsDatabase.PRO_PROFILE_FEATURES)), proFeatures); if (!TextSecurePreferences.isReadReceiptsEnabled(context)) { readReceiptCount = 0; diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt b/app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt index 1d3ef8fa50..fdbaa3c84a 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt @@ -4,11 +4,10 @@ import android.content.Context import android.net.Uri import dagger.Lazy import dagger.hilt.android.qualifiers.ApplicationContext +import network.loki.messenger.libsession_util.MutableConversationVolatileConfig import network.loki.messenger.libsession_util.PRIORITY_PINNED import network.loki.messenger.libsession_util.PRIORITY_VISIBLE -import network.loki.messenger.libsession_util.MutableConversationVolatileConfig import network.loki.messenger.libsession_util.ReadableUserGroupsConfig -import network.loki.messenger.libsession_util.util.BitSet import network.loki.messenger.libsession_util.util.BlindKeyAPI import network.loki.messenger.libsession_util.util.Bytes import network.loki.messenger.libsession_util.util.Conversation @@ -834,7 +833,7 @@ open class Storage @Inject constructor( hasMention = false, isOpenGroupInvitation = false, isSecureMessage = false, - proFeatures = BitSet(), + proFeatures = emptySet(), isGroupMessage = true, isGroupUpdateMessage = true, ) @@ -1051,7 +1050,7 @@ open class Storage @Inject constructor( null, null, emptyList(), - BitSet(), + emptySet(), null, null, emptyList(), @@ -1077,7 +1076,7 @@ open class Storage @Inject constructor( body = null, group = null, attachments = emptyList(), - proFeatures = BitSet(), + proFeatures = emptySet(), messageContent = null, quote = null, linkPreviews = emptyList(), diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/helpers/SQLCipherOpenHelper.java b/app/src/main/java/org/thoughtcrime/securesms/database/helpers/SQLCipherOpenHelper.java index 458170fa1c..d82ba6b813 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/helpers/SQLCipherOpenHelper.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/helpers/SQLCipherOpenHelper.java @@ -272,8 +272,8 @@ public void onCreate(SQLiteDatabase db) { ReceivedMessageHashDatabase.Companion.createAndMigrateTable(db); ProDatabase.Companion.createTable(db); - db.execSQL(MmsDatabase.ADD_PRO_FEATURES_COLUMN); - db.execSQL(SmsDatabase.ADD_PRO_FEATURES_COLUMN); + MmsDatabase.Companion.addProFeatureColumns(db); + SmsDatabase.addProFeatureColumns(db); RecipientSettingsDatabase.Companion.migrateProStatusToProData(db); } @@ -619,8 +619,8 @@ public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { if (oldVersion < lokiV57) { ProDatabase.Companion.createTable(db); - db.execSQL(MmsDatabase.ADD_PRO_FEATURES_COLUMN); - db.execSQL(SmsDatabase.ADD_PRO_FEATURES_COLUMN); + MmsDatabase.Companion.addProFeatureColumns(db); + SmsDatabase.addProFeatureColumns(db); RecipientSettingsDatabase.Companion.migrateProStatusToProData(db); } diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/model/MediaMmsMessageRecord.java b/app/src/main/java/org/thoughtcrime/securesms/database/model/MediaMmsMessageRecord.java index 37d56e2007..239de984d9 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/model/MediaMmsMessageRecord.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/model/MediaMmsMessageRecord.java @@ -26,6 +26,9 @@ import org.thoughtcrime.securesms.mms.SlideDeck; import java.util.List; +import java.util.Set; + +import network.loki.messenger.libsession_util.protocol.ProFeature; /** * Represents the message record model for MMS messages that contain @@ -48,12 +51,12 @@ public MediaMmsMessageRecord(long id, Recipient conversationRecipient, @NonNull List linkPreviews, @NonNull List reactions, boolean hasMention, @Nullable MessageContent messageContent, - long proFeaturesRawValue) + Set proFeatures) { super(id, body, conversationRecipient, individualRecipient, dateSent, dateReceived, threadId, Status.STATUS_NONE, deliveryReceiptCount, mailbox, expiresIn, expireStarted, slideDeck, readReceiptCount, quote, - linkPreviews, reactions, hasMention, messageContent, proFeaturesRawValue); + linkPreviews, reactions, hasMention, messageContent, proFeatures); } @Override diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/model/MessageRecord.java b/app/src/main/java/org/thoughtcrime/securesms/database/model/MessageRecord.java index 3bd0c62eec..ce04203b84 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/model/MessageRecord.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/model/MessageRecord.java @@ -40,8 +40,10 @@ import java.util.List; import java.util.Objects; +import java.util.Set; import network.loki.messenger.R; +import network.loki.messenger.libsession_util.protocol.ProFeature; /** * The base class for message record models that are displayed in @@ -61,7 +63,7 @@ public abstract class MessageRecord extends DisplayRecord { @Nullable private UpdateMessageData groupUpdateMessage; - final long proFeaturesRawValue; + public final Set proFeatures; public abstract boolean isMms(); public abstract boolean isMmsNotification(); @@ -77,7 +79,7 @@ public final MessageId getMessageId() { long expiresIn, long expireStarted, int readReceiptCount, List reactions, boolean hasMention, @Nullable MessageContent messageContent, - long proFeaturesRawValue) + Set proFeatures) { super(body, conversationRecipient, dateSent, dateReceived, threadId, deliveryStatus, deliveryReceiptCount, type, readReceiptCount, messageContent); @@ -87,7 +89,7 @@ public final MessageId getMessageId() { this.expireStarted = expireStarted; this.reactions = reactions; this.hasMention = hasMention; - this.proFeaturesRawValue = proFeaturesRawValue; + this.proFeatures = proFeatures; } public long getId() { diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/model/MessageRecords.kt b/app/src/main/java/org/thoughtcrime/securesms/database/model/MessageRecords.kt deleted file mode 100644 index fc4a22eab2..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/database/model/MessageRecords.kt +++ /dev/null @@ -1,6 +0,0 @@ -package org.thoughtcrime.securesms.database.model - -import network.loki.messenger.libsession_util.protocol.ProMessageFeature -import network.loki.messenger.libsession_util.util.BitSet - -val MessageRecord.proFeatures: BitSet get() = BitSet(proFeaturesRawValue) \ No newline at end of file diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/model/MmsMessageRecord.java b/app/src/main/java/org/thoughtcrime/securesms/database/model/MmsMessageRecord.java index 5dd4e8206f..30e75f7475 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/model/MmsMessageRecord.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/model/MmsMessageRecord.java @@ -11,6 +11,9 @@ import java.util.ArrayList; import java.util.List; +import java.util.Set; + +import network.loki.messenger.libsession_util.protocol.ProFeature; public abstract class MmsMessageRecord extends MessageRecord { private final @NonNull SlideDeck slideDeck; @@ -26,8 +29,8 @@ public abstract class MmsMessageRecord extends MessageRecord { @Nullable Quote quote, @NonNull List linkPreviews, List reactions, boolean hasMention, @Nullable MessageContent messageContent, - long proFeaturesRawValue) { - super(id, body, conversationRecipient, individualRecipient, dateSent, dateReceived, threadId, deliveryStatus, deliveryReceiptCount, type, expiresIn, expireStarted, readReceiptCount, reactions, hasMention, messageContent, proFeaturesRawValue); + Set proFeatures) { + super(id, body, conversationRecipient, individualRecipient, dateSent, dateReceived, threadId, deliveryStatus, deliveryReceiptCount, type, expiresIn, expireStarted, readReceiptCount, reactions, hasMention, messageContent, proFeatures); this.slideDeck = slideDeck; this.quote = quote; this.linkPreviews.addAll(linkPreviews); diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/model/SmsMessageRecord.java b/app/src/main/java/org/thoughtcrime/securesms/database/model/SmsMessageRecord.java index 5b4acdce6d..f9aa2e2846 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/model/SmsMessageRecord.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/model/SmsMessageRecord.java @@ -24,6 +24,9 @@ import org.session.libsession.utilities.recipients.Recipient; import java.util.List; +import java.util.Set; + +import network.loki.messenger.libsession_util.protocol.ProFeature; /** * The message record model which represents standard SMS messages. @@ -42,11 +45,11 @@ public SmsMessageRecord(long id, int status, long expiresIn, long expireStarted, int readReceiptCount, List reactions, boolean hasMention, - long proFeaturesRawValue) { + Set proFeatures) { super(id, body, recipient, individualRecipient, dateSent, dateReceived, threadId, status, deliveryReceiptCount, type, expiresIn, expireStarted, readReceiptCount, reactions, hasMention, null, - proFeaturesRawValue); + proFeatures); } public long getType() { diff --git a/app/src/main/java/org/thoughtcrime/securesms/debugmenu/DebugMenu.kt b/app/src/main/java/org/thoughtcrime/securesms/debugmenu/DebugMenu.kt index cbe98ada34..a23216759c 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/debugmenu/DebugMenu.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/debugmenu/DebugMenu.kt @@ -55,7 +55,7 @@ import androidx.compose.ui.unit.dp import network.loki.messenger.BuildConfig import network.loki.messenger.R import network.loki.messenger.libsession_util.protocol.ProMessageFeature -import network.loki.messenger.libsession_util.util.toBitSet +import network.loki.messenger.libsession_util.protocol.ProProfileFeature import org.session.libsession.messaging.groups.LegacyGroupDeprecationManager import org.thoughtcrime.securesms.debugmenu.DebugMenuViewModel.Commands.* import org.thoughtcrime.securesms.debugmenu.DebugMenuViewModel.Companion.FALSE @@ -65,7 +65,6 @@ import org.thoughtcrime.securesms.debugmenu.DebugMenuViewModel.Companion.SEEN_2 import org.thoughtcrime.securesms.debugmenu.DebugMenuViewModel.Companion.SEEN_3 import org.thoughtcrime.securesms.debugmenu.DebugMenuViewModel.Companion.SEEN_4 import org.thoughtcrime.securesms.debugmenu.DebugMenuViewModel.Companion.TRUE -import org.thoughtcrime.securesms.pro.ProStatusManager import org.thoughtcrime.securesms.ui.AlertDialog import org.thoughtcrime.securesms.ui.Cell import org.thoughtcrime.securesms.ui.DialogButtonData @@ -349,7 +348,7 @@ fun DebugMenu( AnimatedVisibility(uiState.forceIncomingMessagesAsPro) { Column { - for (feature in ProMessageFeature.entries) { + for (feature in (ProMessageFeature.entries + ProProfileFeature.entries)) { DebugCheckboxRow( text = "Message Feature: ${feature.name}", minHeight = 30.dp, @@ -938,7 +937,7 @@ fun PreviewDebugMenu() { forceOtherUsersAsPro = false, forcePostPro = false, forceShortTTl = false, - messageProFeature = listOf(ProMessageFeature.HIGHER_CHARACTER_LIMIT).toBitSet(), + messageProFeature = setOf(ProMessageFeature.HIGHER_CHARACTER_LIMIT), dbInspectorState = DebugMenuViewModel.DatabaseInspectorState.STARTED, debugSubscriptionStatuses = setOf(DebugMenuViewModel.DebugSubscriptionStatus.AUTO_GOOGLE), selectedDebugSubscriptionStatus = DebugMenuViewModel.DebugSubscriptionStatus.AUTO_GOOGLE, diff --git a/app/src/main/java/org/thoughtcrime/securesms/debugmenu/DebugMenuViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/debugmenu/DebugMenuViewModel.kt index aa5a6eb653..88f57881db 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/debugmenu/DebugMenuViewModel.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/debugmenu/DebugMenuViewModel.kt @@ -5,6 +5,7 @@ import android.content.ClipboardManager import android.content.Context import android.os.Build import android.widget.Toast +import androidx.collection.ArraySet import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import dagger.assisted.Assisted @@ -22,13 +23,11 @@ import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch import kotlinx.coroutines.withContext +import network.loki.messenger.libsession_util.ED25519 import network.loki.messenger.libsession_util.PRIORITY_HIDDEN import network.loki.messenger.libsession_util.PRIORITY_VISIBLE -import network.loki.messenger.libsession_util.ED25519 -import network.loki.messenger.libsession_util.protocol.ProMessageFeature -import network.loki.messenger.libsession_util.util.BitSet +import network.loki.messenger.libsession_util.protocol.ProFeature import network.loki.messenger.libsession_util.util.BlindKeyAPI -import network.loki.messenger.libsession_util.util.asSequence import network.loki.messenger.libsession_util.util.toBitSet import org.session.libsession.database.StorageProtocol import org.session.libsession.messaging.file_server.FileServer @@ -358,12 +357,11 @@ class DebugMenuViewModel @AssistedInject constructor( } is Commands.SetMessageProFeature -> { - val features = _uiState.value.messageProFeature.asSequence().toMutableSet() + val features = ArraySet(_uiState.value.messageProFeature) if(command.set) features.add(command.feature) else features.remove(command.feature) - val newFeatures = features.toBitSet() - textSecurePreferences.setDebugMessageFeatures(newFeatures) + textSecurePreferences.setDebugMessageFeatures(features) _uiState.update { - it.copy(messageProFeature = newFeatures) + it.copy(messageProFeature = features) } } @@ -619,7 +617,7 @@ class DebugMenuViewModel @AssistedInject constructor( val forceCurrentUserAsPro: Boolean, val forceOtherUsersAsPro: Boolean, val forceIncomingMessagesAsPro: Boolean, - val messageProFeature: BitSet, + val messageProFeature: Set, val forcePostPro: Boolean, val forceShortTTl: Boolean, val forceDeprecationState: LegacyGroupDeprecationManager.DeprecationState?, @@ -691,7 +689,7 @@ class DebugMenuViewModel @AssistedInject constructor( data class WithinQuickRefund(val set: Boolean) : Commands() data class ForcePostPro(val set: Boolean) : Commands() data class ForceShortTTl(val set: Boolean) : Commands() - data class SetMessageProFeature(val feature: ProMessageFeature, val set: Boolean) : Commands() + data class SetMessageProFeature(val feature: ProFeature, val set: Boolean) : Commands() data class ShowDeprecationChangeDialog(val state: LegacyGroupDeprecationManager.DeprecationState?) : Commands() object HideDeprecationChangeDialog : Commands() object OverrideDeprecationState : Commands() diff --git a/app/src/main/java/org/thoughtcrime/securesms/pro/ProFeatureExt.kt b/app/src/main/java/org/thoughtcrime/securesms/pro/ProFeatureExt.kt new file mode 100644 index 0000000000..86442e9602 --- /dev/null +++ b/app/src/main/java/org/thoughtcrime/securesms/pro/ProFeatureExt.kt @@ -0,0 +1,24 @@ +package org.thoughtcrime.securesms.pro + +import network.loki.messenger.libsession_util.protocol.ProFeature +import network.loki.messenger.libsession_util.protocol.ProMessageFeature +import network.loki.messenger.libsession_util.protocol.ProProfileFeature +import network.loki.messenger.libsession_util.util.BitSet +import network.loki.messenger.libsession_util.util.asSequence +import network.loki.messenger.libsession_util.util.toBitSet + +fun Long.toProMessageFeatures(out: MutableCollection) { + out.addAll(BitSet(this).asSequence()) +} + +fun Long.toProProfileFeatures(out: MutableCollection) { + out.addAll(BitSet(this).asSequence()) +} + +fun Iterable.toProMessageBitSetValue(): Long { + return filterIsInstance().toBitSet().rawValue +} + +fun Iterable.toProProfileBitSetValue(): Long { + return filterIsInstance().toBitSet().rawValue +} \ No newline at end of file diff --git a/app/src/main/java/org/thoughtcrime/securesms/pro/ProStatusManager.kt b/app/src/main/java/org/thoughtcrime/securesms/pro/ProStatusManager.kt index 11436b1f49..248c4338a5 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/pro/ProStatusManager.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/pro/ProStatusManager.kt @@ -31,8 +31,7 @@ import network.loki.messenger.libsession_util.pro.BackendRequests import network.loki.messenger.libsession_util.pro.BackendRequests.PAYMENT_PROVIDER_APP_STORE import network.loki.messenger.libsession_util.pro.BackendRequests.PAYMENT_PROVIDER_GOOGLE_PLAY import network.loki.messenger.libsession_util.pro.ProConfig -import network.loki.messenger.libsession_util.protocol.ProMessageFeature -import network.loki.messenger.libsession_util.util.BitSet +import network.loki.messenger.libsession_util.protocol.ProFeature import network.loki.messenger.libsession_util.util.Conversation import org.session.libsession.messaging.messages.visible.VisibleMessage import org.session.libsession.snode.SnodeClock @@ -46,7 +45,6 @@ import org.session.libsignal.utilities.toHexString import org.thoughtcrime.securesms.auth.LoginStateRepository import org.thoughtcrime.securesms.database.RecipientRepository import org.thoughtcrime.securesms.database.model.MessageRecord -import org.thoughtcrime.securesms.database.model.proFeatures import org.thoughtcrime.securesms.debugmenu.DebugLogGroup import org.thoughtcrime.securesms.debugmenu.DebugMenuViewModel import org.thoughtcrime.securesms.dependencies.ManagerScope @@ -400,7 +398,7 @@ class ProStatusManager @Inject constructor( /** * This will get the list of Pro features from an incoming message */ - fun getMessageProFeatures(message: MessageRecord): BitSet { + fun getMessageProFeatures(message: MessageRecord): Set { // use debug values if any if(prefs.forceIncomingMessagesAsPro()){ return prefs.getDebugMessageFeatures() diff --git a/app/src/main/java/org/thoughtcrime/securesms/service/ExpiringMessageManager.kt b/app/src/main/java/org/thoughtcrime/securesms/service/ExpiringMessageManager.kt index 1a05e6547f..02e744038c 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/service/ExpiringMessageManager.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/service/ExpiringMessageManager.kt @@ -8,7 +8,6 @@ import kotlinx.coroutines.flow.first import kotlinx.coroutines.joinAll import kotlinx.coroutines.launch import kotlinx.coroutines.withTimeoutOrNull -import network.loki.messenger.libsession_util.util.BitSet import network.loki.messenger.libsession_util.util.ExpiryMode import org.session.libsession.messaging.messages.Message import org.session.libsession.messaging.messages.control.ExpirationTimerUpdate @@ -100,7 +99,7 @@ class ExpiringMessageManager @Inject constructor( body = null, group = groupAddress, attachments = emptyList(), - proFeatures = BitSet(), + proFeatures = emptySet(), messageContent = DisappearingMessageUpdate(message.expiryMode), quote = null, linkPreviews = emptyList(),