Convert SignalService, Database, Group, Payment, and other remaining protos to wire.

This commit is contained in:
Cody Henthorne
2023-09-18 15:32:43 -04:00
committed by Alex Hart
parent a6b7d0bcc5
commit efbd5cab85
267 changed files with 7100 additions and 7214 deletions

View File

@@ -14,12 +14,12 @@ fun BodyRangeList?.adjustBodyRanges(bodyAdjustments: List<BodyAdjustment>): Body
return this
}
val newBodyRanges = rangesList.toMutableList()
val newBodyRanges = ranges.toMutableList()
for (adjustment in bodyAdjustments) {
val adjustmentLength = adjustment.oldLength - adjustment.newLength
rangesList.forEachIndexed { listIndex, range ->
ranges.forEachIndexed { listIndex, range ->
val needsRangeStartsAfterAdjustment = range.start > adjustment.startIndex
val needsRangeCoversAdjustment = range.start <= adjustment.startIndex && range.start + range.length >= adjustment.startIndex + adjustment.oldLength
@@ -28,10 +28,10 @@ fun BodyRangeList?.adjustBodyRanges(bodyAdjustments: List<BodyAdjustment>): Body
val newLength: Int? = if (needsRangeCoversAdjustment) newRange.length - adjustmentLength else null
if (newStart != null || newLength != null) {
newBodyRanges[listIndex] = newRange.toBuilder().setStart(newStart ?: newRange.start).setLength(newLength ?: newRange.length).build()
newBodyRanges[listIndex] = newRange.newBuilder().start(newStart ?: newRange.start).length(newLength ?: newRange.length).build()
}
}
}
return BodyRangeList.newBuilder().addAllRanges(newBodyRanges).build()
return BodyRangeList(ranges = newBodyRanges)
}

View File

@@ -35,7 +35,7 @@ import org.thoughtcrime.securesms.recipients.Recipient
import org.thoughtcrime.securesms.recipients.RecipientId
import org.thoughtcrime.securesms.service.webrtc.links.CallLinkRoomId
import org.whispersystems.signalservice.api.push.ServiceId.ACI
import org.whispersystems.signalservice.internal.push.SignalServiceProtos.SyncMessage.CallEvent
import org.whispersystems.signalservice.internal.push.SyncMessage.CallEvent
import java.util.UUID
import java.util.concurrent.TimeUnit
@@ -1179,9 +1179,9 @@ class CallTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTabl
}
@JvmStatic
fun from(type: CallEvent.Type): Type? {
fun from(type: CallEvent.Type?): Type? {
return when (type) {
CallEvent.Type.UNKNOWN_TYPE -> null
null, CallEvent.Type.UNKNOWN_TYPE -> null
CallEvent.Type.AUDIO_CALL -> AUDIO_CALL
CallEvent.Type.VIDEO_CALL -> VIDEO_CALL
CallEvent.Type.GROUP_CALL -> GROUP_CALL
@@ -1207,9 +1207,9 @@ class CallTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTabl
}
@JvmStatic
fun from(direction: CallEvent.Direction): Direction? {
fun from(direction: CallEvent.Direction?): Direction? {
return when (direction) {
CallEvent.Direction.UNKNOWN_DIRECTION -> null
null, CallEvent.Direction.UNKNOWN_DIRECTION -> null
CallEvent.Direction.INCOMING -> INCOMING
CallEvent.Direction.OUTGOING -> OUTGOING
}
@@ -1284,9 +1284,9 @@ class CallTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTabl
}
@JvmStatic
fun from(event: CallEvent.Event): Event? {
fun from(event: CallEvent.Event?): Event? {
return when (event) {
CallEvent.Event.UNKNOWN_ACTION -> null
null, CallEvent.Event.UNKNOWN_ACTION -> null
CallEvent.Event.ACCEPTED -> ACCEPTED
CallEvent.Event.NOT_ACCEPTED -> NOT_ACCEPTED
CallEvent.Event.DELETE -> DELETE

View File

@@ -70,7 +70,7 @@ class ChatColorsTable(context: Context, databaseHelper: SignalDatabase) : Databa
val db: SQLiteDatabase = databaseHelper.signalWritableDatabase
val values = ContentValues(1).apply {
put(CHAT_COLORS, chatColors.serialize().toByteArray())
put(CHAT_COLORS, chatColors.serialize().encode())
}
val rowId = db.insert(TABLE_NAME, null, values)
@@ -90,7 +90,7 @@ class ChatColorsTable(context: Context, databaseHelper: SignalDatabase) : Databa
val db: SQLiteDatabase = databaseHelper.signalWritableDatabase
val values = ContentValues(1).apply {
put(CHAT_COLORS, chatColors.serialize().toByteArray())
put(CHAT_COLORS, chatColors.serialize().encode())
}
val rowsUpdated = db.update(TABLE_NAME, values, ID_WHERE, SqlUtil.buildArgs(chatColors.id.longValue))
@@ -131,6 +131,6 @@ class ChatColorsTable(context: Context, databaseHelper: SignalDatabase) : Databa
private fun Cursor.getId(): Long = CursorUtil.requireLong(this, ID)
private fun Cursor.getChatColors(): ChatColors = ChatColors.forChatColor(
ChatColors.Id.forLongValue(getId()),
ChatColor.parseFrom(CursorUtil.requireBlob(this, CHAT_COLORS))
ChatColor.ADAPTER.decode(CursorUtil.requireBlob(this, CHAT_COLORS))
)
}

View File

@@ -695,8 +695,8 @@ class GroupTable(context: Context?, databaseHelper: SignalDatabase?) : DatabaseT
Log.w(TAG, "No group entry. Creating restore placeholder for $groupId")
create(
groupMasterKey,
DecryptedGroup.newBuilder()
.setRevision(GroupsV2StateProcessor.RESTORE_PLACEHOLDER_REVISION)
DecryptedGroup.Builder()
.revision(GroupsV2StateProcessor.RESTORE_PLACEHOLDER_REVISION)
.build(),
true
)
@@ -765,7 +765,7 @@ class GroupTable(context: Context?, databaseHelper: SignalDatabase?) : DatabaseT
values.put(V2_MASTER_KEY, groupMasterKey.serialize())
values.put(V2_REVISION, groupState.revision)
values.put(V2_DECRYPTED_GROUP, groupState.toByteArray())
values.put(V2_DECRYPTED_GROUP, groupState.encode())
membershipValues.clear()
membershipValues.addAll(groupMembers.toContentValues(groupId))
} else {
@@ -790,8 +790,8 @@ class GroupTable(context: Context?, databaseHelper: SignalDatabase?) : DatabaseT
writableDatabase.endTransaction()
}
if (groupState != null && groupState.hasDisappearingMessagesTimer()) {
recipients.setExpireMessages(groupRecipientId, groupState.disappearingMessagesTimer.duration)
if (groupState?.disappearingMessagesTimer != null) {
recipients.setExpireMessages(groupRecipientId, groupState.disappearingMessagesTimer!!.duration)
}
if (groupId.isMms || Recipient.resolved(groupRecipientId).isProfileSharing) {
@@ -849,8 +849,8 @@ class GroupTable(context: Context?, databaseHelper: SignalDatabase?) : DatabaseT
writableDatabase.withinTransaction { db ->
val record = getGroup(groupIdV1).get()
val newMembers: MutableList<RecipientId> = decryptedGroup.membersList.toAciList().toRecipientIds()
val pendingMembers: List<RecipientId> = DecryptedGroupUtil.pendingToServiceIdList(decryptedGroup.pendingMembersList).toRecipientIds()
val newMembers: MutableList<RecipientId> = decryptedGroup.members.toAciList().toRecipientIds()
val pendingMembers: List<RecipientId> = DecryptedGroupUtil.pendingToServiceIdList(decryptedGroup.pendingMembers).toRecipientIds()
newMembers.addAll(pendingMembers)
val droppedMembers: List<RecipientId> = SetUtil.difference(record.members, newMembers).toList()
@@ -895,7 +895,7 @@ class GroupTable(context: Context?, databaseHelper: SignalDatabase?) : DatabaseT
val contentValues = ContentValues()
contentValues.put(TITLE, title)
contentValues.put(V2_REVISION, decryptedGroup.revision)
contentValues.put(V2_DECRYPTED_GROUP, decryptedGroup.toByteArray())
contentValues.put(V2_DECRYPTED_GROUP, decryptedGroup.encode())
contentValues.put(ACTIVE, if (gv2GroupActive(decryptedGroup)) 1 else 0)
if (existingGroup.isPresent && existingGroup.get().unmigratedV1Members.isNotEmpty() && existingGroup.get().isV2Group) {
@@ -903,11 +903,11 @@ class GroupTable(context: Context?, databaseHelper: SignalDatabase?) : DatabaseT
val change = GroupChangeReconstruct.reconstructGroupChange(existingGroup.get().requireV2GroupProperties().decryptedGroup, decryptedGroup)
val addedMembers: Set<RecipientId> = change.newMembersList.toAciList().toRecipientIds().toSet()
val addedMembers: Set<RecipientId> = change.newMembers.toAciList().toRecipientIds().toSet()
val removedMembers: Set<RecipientId> = DecryptedGroupUtil.removedMembersServiceIdList(change).toRecipientIds().toSet()
val addedInvites: Set<RecipientId> = DecryptedGroupUtil.pendingToServiceIdList(change.newPendingMembersList).toRecipientIds().toSet()
val addedInvites: Set<RecipientId> = DecryptedGroupUtil.pendingToServiceIdList(change.newPendingMembers).toRecipientIds().toSet()
val removedInvites: Set<RecipientId> = DecryptedGroupUtil.removedPendingMembersServiceIdList(change).toRecipientIds().toSet()
val acceptedInvites: Set<RecipientId> = change.promotePendingMembersList.toAciList().toRecipientIds().toSet()
val acceptedInvites: Set<RecipientId> = change.promotePendingMembers.toAciList().toRecipientIds().toSet()
unmigratedV1Members -= addedMembers
unmigratedV1Members -= removedMembers
@@ -941,8 +941,8 @@ class GroupTable(context: Context?, databaseHelper: SignalDatabase?) : DatabaseT
performMembershipUpdate(database, groupId, groupMembers)
}
if (decryptedGroup.hasDisappearingMessagesTimer()) {
recipients.setExpireMessages(groupRecipientId, decryptedGroup.disappearingMessagesTimer.duration)
if (decryptedGroup.disappearingMessagesTimer != null) {
recipients.setExpireMessages(groupRecipientId, decryptedGroup.disappearingMessagesTimer!!.duration)
}
if (groupId.isMms || Recipient.resolved(groupRecipientId).isProfileSharing) {
@@ -1192,18 +1192,18 @@ class GroupTable(context: Context?, databaseHelper: SignalDatabase?) : DatabaseT
class V2GroupProperties(val groupMasterKey: GroupMasterKey, val groupRevision: Int, val decryptedGroupBytes: ByteArray) {
val decryptedGroup: DecryptedGroup by lazy {
DecryptedGroup.parseFrom(decryptedGroupBytes)
DecryptedGroup.ADAPTER.decode(decryptedGroupBytes)
}
val bannedMembers: Set<ServiceId> by lazy {
DecryptedGroupUtil.bannedMembersToServiceIdSet(decryptedGroup.bannedMembersList)
DecryptedGroupUtil.bannedMembersToServiceIdSet(decryptedGroup.bannedMembers)
}
fun isAdmin(recipient: Recipient): Boolean {
val aci = recipient.aci
return if (aci.isPresent) {
decryptedGroup.membersList.findMemberByAci(aci.get())
decryptedGroup.members.findMemberByAci(aci.get())
.map { it.role == Member.Role.ADMINISTRATOR }
.orElse(false)
} else {
@@ -1224,7 +1224,7 @@ class GroupTable(context: Context?, databaseHelper: SignalDatabase?) : DatabaseT
var memberLevel: Optional<MemberLevel> = Optional.empty()
if (serviceId is ACI) {
memberLevel = decryptedGroup.membersList.findMemberByAci(serviceId)
memberLevel = decryptedGroup.members.findMemberByAci(serviceId)
.map { member ->
if (member.role == Member.Role.ADMINISTRATOR) {
MemberLevel.ADMINISTRATOR
@@ -1235,12 +1235,12 @@ class GroupTable(context: Context?, databaseHelper: SignalDatabase?) : DatabaseT
}
if (memberLevel.isAbsent()) {
memberLevel = decryptedGroup.pendingMembersList.findPendingByServiceId(serviceId)
memberLevel = decryptedGroup.pendingMembers.findPendingByServiceId(serviceId)
.map { MemberLevel.PENDING_MEMBER }
}
if (memberLevel.isAbsent() && serviceId is ACI) {
memberLevel = decryptedGroup.requestingMembersList.findRequestingByAci(serviceId)
memberLevel = decryptedGroup.requestingMembers.findRequestingByAci(serviceId)
.map { _ -> MemberLevel.REQUESTING_MEMBER }
}
@@ -1258,12 +1258,12 @@ class GroupTable(context: Context?, databaseHelper: SignalDatabase?) : DatabaseT
fun getMemberRecipientIds(memberSet: MemberSet): List<RecipientId> {
val includeSelf = memberSet.includeSelf
val selfAci = SignalStore.account().requireAci()
val recipients: MutableList<RecipientId> = ArrayList(decryptedGroup.membersCount + decryptedGroup.pendingMembersCount)
val recipients: MutableList<RecipientId> = ArrayList(decryptedGroup.members.size + decryptedGroup.pendingMembers.size)
var unknownMembers = 0
var unknownPending = 0
for (aci in decryptedGroup.membersList.toAciListWithUnknowns()) {
for (aci in decryptedGroup.members.toAciListWithUnknowns()) {
if (aci.isUnknown) {
unknownMembers++
} else if (includeSelf || selfAci != aci) {
@@ -1272,7 +1272,7 @@ class GroupTable(context: Context?, databaseHelper: SignalDatabase?) : DatabaseT
}
if (memberSet.includePending) {
for (serviceId in DecryptedGroupUtil.pendingToServiceIdList(decryptedGroup.pendingMembersList)) {
for (serviceId in DecryptedGroupUtil.pendingToServiceIdList(decryptedGroup.pendingMembers)) {
if (serviceId.isUnknown) {
unknownPending++
} else if (includeSelf || selfAci != serviceId) {
@@ -1290,7 +1290,7 @@ class GroupTable(context: Context?, databaseHelper: SignalDatabase?) : DatabaseT
fun getMemberServiceIds(): List<ServiceId> {
return decryptedGroup
.membersList
.members
.asSequence()
.map { ACI.parseOrNull(it.aciBytes) }
.filterNotNull()
@@ -1368,8 +1368,8 @@ class GroupTable(context: Context?, databaseHelper: SignalDatabase?) : DatabaseT
private fun gv2GroupActive(decryptedGroup: DecryptedGroup): Boolean {
val aci = SignalStore.account().requireAci()
return decryptedGroup.membersList.findMemberByAci(aci).isPresent ||
DecryptedGroupUtil.findPendingByServiceId(decryptedGroup.pendingMembersList, aci).isPresent
return decryptedGroup.members.findMemberByAci(aci).isPresent ||
DecryptedGroupUtil.findPendingByServiceId(decryptedGroup.pendingMembers, aci).isPresent
}
private fun List<ServiceId>.toRecipientIds(): MutableList<RecipientId> {
@@ -1412,7 +1412,7 @@ class GroupTable(context: Context?, databaseHelper: SignalDatabase?) : DatabaseT
}
private fun getV2GroupMembers(decryptedGroup: DecryptedGroup, shouldRetry: Boolean): List<RecipientId> {
val ids: List<RecipientId> = decryptedGroup.membersList.toAciList().toRecipientIds()
val ids: List<RecipientId> = decryptedGroup.members.toAciList().toRecipientIds()
return if (RemappedRecords.getInstance().areAnyRemapped(ids)) {
if (shouldRetry) {

View File

@@ -23,6 +23,7 @@ import java.util.Collections;
import java.util.List;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.stream.Collectors;
public final class MentionUtil {
@@ -93,26 +94,29 @@ public final class MentionUtil {
return null;
}
BodyRangeList.Builder builder = BodyRangeList.newBuilder();
for (Mention mention : mentions) {
String uuid = Recipient.resolved(mention.getRecipientId()).requireAci().toString();
builder.addRanges(BodyRangeList.BodyRange.newBuilder()
.setMentionUuid(uuid)
.setStart(mention.getStart())
.setLength(mention.getLength()));
}
BodyRangeList.Builder builder = new BodyRangeList.Builder();
builder.ranges(
mentions.stream()
.map(mention -> {
String uuid = Recipient.resolved(mention.getRecipientId()).requireAci().toString();
return new BodyRangeList.BodyRange.Builder()
.mentionUuid(uuid)
.start(mention.getStart())
.length(mention.getLength())
.build();
})
.collect(Collectors.toList())
);
return builder.build();
}
public static @NonNull List<Mention> bodyRangeListToMentions(@Nullable BodyRangeList bodyRanges) {
if (bodyRanges != null) {
return Stream.of(bodyRanges.getRangesList())
.filter(bodyRange -> bodyRange.getAssociatedValueCase() == BodyRangeList.BodyRange.AssociatedValueCase.MENTIONUUID)
return Stream.of(bodyRanges.ranges)
.filter(bodyRange -> bodyRange.mentionUuid != null)
.map(mention -> {
RecipientId id = Recipient.externalPush(ServiceId.parseOrThrow(mention.getMentionUuid())).getId();
return new Mention(id, mention.getStart(), mention.getLength());
RecipientId id = Recipient.externalPush(ServiceId.parseOrThrow(mention.mentionUuid)).getId();
return new Mention(id, mention.start, mention.length);
})
.toList();
} else {

View File

@@ -18,7 +18,7 @@ import org.thoughtcrime.securesms.util.FeatureFlags
import org.thoughtcrime.securesms.util.RecipientAccessList
import org.whispersystems.signalservice.api.crypto.ContentHint
import org.whispersystems.signalservice.api.messages.SendMessageResult
import org.whispersystems.signalservice.internal.push.SignalServiceProtos
import org.whispersystems.signalservice.internal.push.Content
/**
* Stores a rolling buffer of all outgoing messages. Used for the retry logic required for sender key.
@@ -191,7 +191,7 @@ class MessageSendLogTables constructor(context: Context?, databaseHelper: Signal
return -1
}
val content: SignalServiceProtos.Content = results.first { it.isSuccess && it.success.content.isPresent }.success.content.get()
val content: Content = results.first { it.isSuccess && it.success.content.isPresent }.success.content.get()
return insert(recipientDevices, sentTimestamp, content, contentHint, listOf(messageId), urgent)
}
@@ -228,14 +228,14 @@ class MessageSendLogTables constructor(context: Context?, databaseHelper: Signal
return payloadId
}
private fun insert(recipients: List<RecipientDevice>, dateSent: Long, content: SignalServiceProtos.Content, contentHint: ContentHint, messageIds: List<MessageId>, urgent: Boolean): Long {
private fun insert(recipients: List<RecipientDevice>, dateSent: Long, content: Content, contentHint: ContentHint, messageIds: List<MessageId>, urgent: Boolean): Long {
val db = databaseHelper.signalWritableDatabase
db.beginTransaction()
try {
val payloadValues = ContentValues().apply {
put(MslPayloadTable.DATE_SENT, dateSent)
put(MslPayloadTable.CONTENT, content.toByteArray())
put(MslPayloadTable.CONTENT, content.encode())
put(MslPayloadTable.CONTENT_HINT, contentHint.type)
put(MslPayloadTable.URGENT, urgent.toInt())
}
@@ -300,7 +300,7 @@ class MessageSendLogTables constructor(context: Context?, databaseHelper: Signal
return MessageLogEntry(
recipientId = RecipientId.from(CursorUtil.requireLong(entryCursor, MslRecipientTable.RECIPIENT_ID)),
dateSent = CursorUtil.requireLong(entryCursor, MslPayloadTable.DATE_SENT),
content = SignalServiceProtos.Content.parseFrom(CursorUtil.requireBlob(entryCursor, MslPayloadTable.CONTENT)),
content = Content.ADAPTER.decode(CursorUtil.requireBlob(entryCursor, MslPayloadTable.CONTENT)),
contentHint = ContentHint.fromType(CursorUtil.requireInt(entryCursor, MslPayloadTable.CONTENT_HINT)),
urgent = entryCursor.requireBoolean(MslPayloadTable.URGENT),
relatedMessages = messageIds

View File

@@ -25,7 +25,6 @@ import androidx.annotation.VisibleForTesting
import androidx.core.content.contentValuesOf
import com.google.android.mms.pdu_alt.NotificationInd
import com.google.android.mms.pdu_alt.PduHeaders
import com.google.protobuf.InvalidProtocolBufferException
import org.json.JSONArray
import org.json.JSONException
import org.json.JSONObject
@@ -142,7 +141,7 @@ import org.thoughtcrime.securesms.util.Util
import org.thoughtcrime.securesms.util.isStory
import org.whispersystems.signalservice.api.messages.multidevice.ReadMessage
import org.whispersystems.signalservice.api.push.ServiceId
import org.whispersystems.signalservice.internal.push.SignalServiceProtos.SyncMessage
import org.whispersystems.signalservice.internal.push.SyncMessage
import java.io.Closeable
import java.io.IOException
import java.util.LinkedList
@@ -523,8 +522,8 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
val bodyRanges: BodyRangeList? = if (data != null) {
try {
BodyRangeList.parseFrom(data)
} catch (e: InvalidProtocolBufferException) {
BodyRangeList.ADAPTER.decode(data)
} catch (e: IOException) {
Log.w(TAG, "Unable to parse quote body ranges", e)
null
}
@@ -541,12 +540,12 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
if (data != null) {
try {
val bodyRanges = BodyRangeList
.parseFrom(data)
.rangesList
.filter { bodyRange -> bodyRange.associatedValueCase != BodyRangeList.BodyRange.AssociatedValueCase.MENTIONUUID }
.ADAPTER.decode(data)
.ranges
.filter { bodyRange -> bodyRange.mentionUuid == null }
return BodyRangeList.newBuilder().addAllRanges(bodyRanges).build()
} catch (e: InvalidProtocolBufferException) {
return BodyRangeList(ranges = bodyRanges)
} catch (e: IOException) {
Log.w(TAG, "Unable to parse quote body ranges", e)
}
}
@@ -847,14 +846,13 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
val messageId: MessageId = writableDatabase.withinTransaction { db ->
val self = Recipient.self()
val markRead = joinedUuids.contains(self.requireServiceId().rawUuid) || self.id == sender
val updateDetails: ByteArray = GroupCallUpdateDetails.newBuilder()
.setEraId(eraId)
.setStartedCallUuid(Recipient.resolved(sender).requireServiceId().toString())
.setStartedCallTimestamp(timestamp)
.addAllInCallUuids(joinedUuids.map { it.toString() })
.setIsCallFull(isCallFull)
.build()
.toByteArray()
val updateDetails: ByteArray = GroupCallUpdateDetails(
eraId = eraId,
startedCallUuid = Recipient.resolved(sender).requireServiceId().toString(),
startedCallTimestamp = timestamp,
inCallUuids = joinedUuids.map { it.toString() },
isCallFull = isCallFull
).encode()
val values = contentValuesOf(
FROM_RECIPIENT_ID to sender.serialize(),
@@ -893,7 +891,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
val updateDetail = GroupCallUpdateDetailsUtil.parse(message.body)
val contentValues = contentValuesOf(
BODY to Base64.encodeBytes(updateDetail.toBuilder().setStartedCallTimestamp(timestamp).build().toByteArray()),
BODY to Base64.encodeBytes(updateDetail.newBuilder().startedCallTimestamp(timestamp).build().encode()),
DATE_SENT to timestamp,
DATE_RECEIVED to timestamp
)
@@ -1157,14 +1155,8 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
fun insertProfileNameChangeMessages(recipient: Recipient, newProfileName: String, previousProfileName: String) {
writableDatabase.withinTransaction { db ->
val groupRecords = groups.getGroupsContainingMember(recipient.id, false)
val profileChangeDetails = ProfileChangeDetails.newBuilder()
.setProfileNameChange(
ProfileChangeDetails.StringChange.newBuilder()
.setNew(newProfileName)
.setPrevious(previousProfileName)
)
.build()
.toByteArray()
val profileChangeDetails = ProfileChangeDetails(profileNameChange = ProfileChangeDetails.StringChange(previous = previousProfileName, newValue = newProfileName))
.encode()
val threadIdsToUpdate = mutableListOf<Long?>().apply {
add(threads.getThreadIdFor(recipient.id))
@@ -1294,7 +1286,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
READ to 1,
TYPE to MessageTypes.THREAD_MERGE_TYPE,
THREAD_ID to threadId,
BODY to Base64.encodeBytes(event.toByteArray())
BODY to Base64.encodeBytes(event.encode())
)
.run()
ApplicationDependencies.getDatabaseObserver().notifyConversationListeners(threadId)
@@ -1313,7 +1305,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
READ to 1,
TYPE to MessageTypes.SESSION_SWITCHOVER_TYPE,
THREAD_ID to threadId,
BODY to Base64.encodeBytes(event.toByteArray())
BODY to Base64.encodeBytes(event.encode())
)
.run()
ApplicationDependencies.getDatabaseObserver().notifyConversationListeners(threadId)
@@ -2554,15 +2546,15 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
)
} else {
val giftBadge: GiftBadge? = if (body != null && MessageTypes.isGiftBadge(outboxType)) {
GiftBadge.parseFrom(Base64.decode(body))
GiftBadge.ADAPTER.decode(Base64.decode(body))
} else {
null
}
val messageRanges: BodyRangeList? = if (messageRangesData != null) {
try {
BodyRangeList.parseFrom(messageRangesData)
} catch (e: InvalidProtocolBufferException) {
BodyRangeList.ADAPTER.decode(messageRangesData)
} catch (e: IOException) {
Log.w(TAG, "Error parsing message ranges", e)
null
}
@@ -2648,15 +2640,15 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
contentValues.put(QUOTE_TYPE, retrieved.quote.type.code)
contentValues.put(QUOTE_MISSING, if (retrieved.quote.isOriginalMissing) 1 else 0)
val quoteBodyRanges: BodyRangeList.Builder = retrieved.quote.bodyRanges?.toBuilder() ?: BodyRangeList.newBuilder()
val quoteBodyRanges: BodyRangeList.Builder = retrieved.quote.bodyRanges?.newBuilder() ?: BodyRangeList.Builder()
val mentionsList = MentionUtil.mentionsToBodyRangeList(retrieved.quote.mentions)
if (mentionsList != null) {
quoteBodyRanges.addAllRanges(mentionsList.rangesList)
quoteBodyRanges.ranges += mentionsList.ranges
}
if (quoteBodyRanges.rangesCount > 0) {
contentValues.put(QUOTE_BODY_RANGES, quoteBodyRanges.build().toByteArray())
if (quoteBodyRanges.ranges.isNotEmpty()) {
contentValues.put(QUOTE_BODY_RANGES, quoteBodyRanges.build().encode())
}
quoteAttachments += retrieved.quote.attachments
@@ -2925,12 +2917,12 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
.run()
.use { cursor ->
if (cursor.moveToFirst()) {
val giftBadge = GiftBadge.parseFrom(Base64.decode(cursor.requireNonNullString(BODY)))
val updatedBadge = giftBadge.toBuilder().setRedemptionState(redemptionState).build()
val giftBadge = GiftBadge.ADAPTER.decode(Base64.decode(cursor.requireNonNullString(BODY)))
val updatedBadge = giftBadge.newBuilder().redemptionState(redemptionState).build()
updated = db
.update(TABLE_NAME)
.values(BODY to Base64.encodeBytes(updatedBadge.toByteArray()))
.values(BODY to Base64.encodeBytes(updatedBadge.encode()))
.where("$ID = ?", messageId)
.run() > 0
@@ -3113,18 +3105,18 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
val adjustedQuoteBodyRanges = message.outgoingQuote.bodyRanges.adjustBodyRanges(updated.bodyAdjustments)
val quoteBodyRanges: BodyRangeList.Builder = if (adjustedQuoteBodyRanges != null) {
adjustedQuoteBodyRanges.toBuilder()
adjustedQuoteBodyRanges.newBuilder()
} else {
BodyRangeList.newBuilder()
BodyRangeList.Builder()
}
val mentionsList = MentionUtil.mentionsToBodyRangeList(updated.mentions)
if (mentionsList != null) {
quoteBodyRanges.addAllRanges(mentionsList.rangesList)
quoteBodyRanges.ranges += mentionsList.ranges
}
if (quoteBodyRanges.rangesCount > 0) {
contentValues.put(QUOTE_BODY_RANGES, quoteBodyRanges.build().toByteArray())
if (quoteBodyRanges.ranges.isNotEmpty()) {
contentValues.put(QUOTE_BODY_RANGES, quoteBodyRanges.build().encode())
}
if (editedMessage == null) {
@@ -3252,7 +3244,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
contentValues.put(BODY, body)
contentValues.put(MENTIONS_SELF, if (mentionsSelf) 1 else 0)
if (messageRanges != null) {
contentValues.put(MESSAGE_RANGES, messageRanges.toByteArray())
contentValues.put(MESSAGE_RANGES, messageRanges.encode())
}
val (messageId, insertedAttachments) = writableDatabase.withinTransaction { db ->
@@ -4294,12 +4286,12 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
val bytes: ByteArray? = cursor.requireBlob(EXPORT_STATE)
if (bytes == null) {
MessageExportState.getDefaultInstance()
MessageExportState()
} else {
try {
MessageExportState.parseFrom(bytes)
} catch (e: InvalidProtocolBufferException) {
MessageExportState.getDefaultInstance()
MessageExportState.ADAPTER.decode(bytes)
} catch (e: IOException) {
MessageExportState()
}
}
} ?: throw NoSuchMessageException("The requested message does not exist.")
@@ -4333,7 +4325,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
private fun setMessageExportState(messageId: MessageId, messageExportState: MessageExportState) {
writableDatabase
.update(TABLE_NAME)
.values(EXPORT_STATE to messageExportState.toByteArray())
.values(EXPORT_STATE to messageExportState.encode())
.where("$ID = ?", messageId.id)
.run()
}
@@ -4573,7 +4565,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
}
fun setTimestampReadFromSyncMessageProto(readMessages: List<SyncMessage.Read>, proposedExpireStarted: Long, threadToLatestRead: MutableMap<Long, Long>): Collection<SyncMessageId> {
val reads: List<ReadMessage> = readMessages.map { r -> ReadMessage(ServiceId.parseOrThrow(r.senderAci), r.timestamp) }
val reads: List<ReadMessage> = readMessages.map { r -> ReadMessage(ServiceId.parseOrThrow(r.senderAci!!), r.timestamp!!) }
return setTimestampReadFromSyncMessage(reads, proposedExpireStarted, threadToLatestRead)
}
@@ -4920,8 +4912,8 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
if (data != null) {
try {
bodyRanges[CursorUtil.requireLong(cursor, ID)] = BodyRangeList.parseFrom(data)
} catch (e: InvalidProtocolBufferException) {
bodyRanges[CursorUtil.requireLong(cursor, ID)] = BodyRangeList.ADAPTER.decode(data)
} catch (e: IOException) {
Log.w(TAG, "Unable to parse body ranges for search", e)
}
}
@@ -5136,11 +5128,11 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
}
override fun getMessageExportStateForCurrentRecord(): MessageExportState {
val messageExportState = CursorUtil.requireBlob(cursor, EXPORT_STATE) ?: return MessageExportState.getDefaultInstance()
val messageExportState = CursorUtil.requireBlob(cursor, EXPORT_STATE) ?: return MessageExportState()
return try {
MessageExportState.parseFrom(messageExportState)
} catch (e: InvalidProtocolBufferException) {
MessageExportState.getDefaultInstance()
MessageExportState.ADAPTER.decode(messageExportState)
} catch (e: IOException) {
MessageExportState()
}
}
@@ -5192,7 +5184,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
val slideDeck = SlideDeck(MmsNotificationAttachment(status, messageSize))
val giftBadge: GiftBadge? = if (body != null && MessageTypes.isGiftBadge(mailbox)) {
try {
GiftBadge.parseFrom(Base64.decode(body))
GiftBadge.ADAPTER.decode(Base64.decode(body))
} catch (e: IOException) {
Log.w(TAG, "Error parsing gift badge", e)
null
@@ -5286,8 +5278,8 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
val messageRanges: BodyRangeList? = if (messageRangesData != null) {
try {
BodyRangeList.parseFrom(messageRangesData)
} catch (e: InvalidProtocolBufferException) {
BodyRangeList.ADAPTER.decode(messageRangesData)
} catch (e: IOException) {
Log.w(TAG, "Error parsing message ranges", e)
null
}
@@ -5297,7 +5289,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
val giftBadge: GiftBadge? = if (body != null && MessageTypes.isGiftBadge(box)) {
try {
GiftBadge.parseFrom(Base64.decode(body))
GiftBadge.ADAPTER.decode(Base64.decode(body))
} catch (e: IOException) {
Log.w(TAG, "Error parsing gift badge", e)
null

View File

@@ -4,8 +4,6 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.annimon.stream.Stream;
import com.google.protobuf.ByteString;
import com.google.protobuf.InvalidProtocolBufferException;
import com.mobilecoin.lib.KeyImage;
import com.mobilecoin.lib.Receipt;
import com.mobilecoin.lib.RistrettoPublic;
@@ -14,40 +12,44 @@ import com.mobilecoin.lib.exceptions.SerializationException;
import org.thoughtcrime.securesms.payments.proto.PaymentMetaData;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import okio.ByteString;
public final class PaymentMetaDataUtil {
public static PaymentMetaData parseOrThrow(byte[] requireBlob) {
try {
return PaymentMetaData.parseFrom(requireBlob);
} catch (InvalidProtocolBufferException e) {
return PaymentMetaData.ADAPTER.decode(requireBlob);
} catch (IOException e) {
throw new IllegalStateException(e);
}
}
public static @NonNull PaymentMetaData fromReceipt(@Nullable byte[] receipt) throws SerializationException {
PaymentMetaData.MobileCoinTxoIdentification.Builder builder = PaymentMetaData.MobileCoinTxoIdentification.newBuilder();
PaymentMetaData.MobileCoinTxoIdentification.Builder builder = new PaymentMetaData.MobileCoinTxoIdentification.Builder();
if (receipt != null) {
addReceiptData(receipt, builder);
}
return PaymentMetaData.newBuilder().setMobileCoinTxoIdentification(builder).build();
return new PaymentMetaData.Builder().mobileCoinTxoIdentification(builder.build()).build();
}
public static @NonNull PaymentMetaData fromKeysAndImages(@NonNull List<ByteString> publicKeys, @NonNull List<ByteString> keyImages) {
PaymentMetaData.MobileCoinTxoIdentification.Builder builder = PaymentMetaData.MobileCoinTxoIdentification.newBuilder();
PaymentMetaData.MobileCoinTxoIdentification.Builder builder = new PaymentMetaData.MobileCoinTxoIdentification.Builder();
builder.addAllKeyImages(keyImages);
builder.addAllPublicKey(publicKeys);
builder.keyImages(keyImages);
builder.publicKey(publicKeys);
return PaymentMetaData.newBuilder().setMobileCoinTxoIdentification(builder).build();
return new PaymentMetaData.Builder().mobileCoinTxoIdentification(builder.build()).build();
}
public static @NonNull PaymentMetaData fromReceiptAndTransaction(@Nullable byte[] receipt, @Nullable byte[] transaction) throws SerializationException {
PaymentMetaData.MobileCoinTxoIdentification.Builder builder = PaymentMetaData.MobileCoinTxoIdentification.newBuilder();
PaymentMetaData.MobileCoinTxoIdentification.Builder builder = new PaymentMetaData.MobileCoinTxoIdentification.Builder();
if (transaction != null) {
addTransactionData(transaction, builder);
@@ -55,7 +57,7 @@ public final class PaymentMetaDataUtil {
addReceiptData(receipt, builder);
}
return PaymentMetaData.newBuilder().setMobileCoinTxoIdentification(builder).build();
return new PaymentMetaData.Builder().mobileCoinTxoIdentification(builder.build()).build();
}
private static void addReceiptData(@NonNull byte[] receipt, PaymentMetaData.MobileCoinTxoIdentification.Builder builder) throws SerializationException {
@@ -66,19 +68,25 @@ public final class PaymentMetaDataUtil {
private static void addTransactionData(@NonNull byte[] transactionBytes, PaymentMetaData.MobileCoinTxoIdentification.Builder builder) throws SerializationException {
Transaction transaction = Transaction.fromBytes(transactionBytes);
Set<KeyImage> keyImages = transaction.getKeyImages();
List<ByteString> newKeyImages = new ArrayList<>(builder.keyImages);
for (KeyImage keyImage : keyImages) {
builder.addKeyImages(ByteString.copyFrom(keyImage.getData()));
newKeyImages.add(ByteString.of(keyImage.getData()));
}
builder.keyImages(newKeyImages);
for (RistrettoPublic publicKey : transaction.getOutputPublicKeys()) {
addPublicKey(builder, publicKey);
}
}
private static void addPublicKey(@NonNull PaymentMetaData.MobileCoinTxoIdentification.Builder builder, @NonNull RistrettoPublic publicKey) {
builder.addPublicKey(ByteString.copyFrom(publicKey.getKeyBytes()));
List<ByteString> publicKeys = new ArrayList<>(builder.publicKey);
publicKeys.add(ByteString.of(publicKey.getKeyBytes()));
builder.publicKey(publicKeys);
}
public static byte[] receiptPublic(@NonNull PaymentMetaData paymentMetaData) {
return Stream.of(paymentMetaData.getMobileCoinTxoIdentification().getPublicKeyList()).single().toByteArray();
return Stream.of(paymentMetaData.mobileCoinTxoIdentification.publicKey).single().toByteArray();
}
}

View File

@@ -11,11 +11,12 @@ import androidx.annotation.WorkerThread;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import com.google.protobuf.InvalidProtocolBufferException;
import com.mobilecoin.lib.exceptions.SerializationException;
import org.signal.core.util.CursorExtensionsKt;
import org.signal.core.util.CursorUtil;
import org.signal.core.util.SQLiteDatabaseExtensionsKt;
import org.signal.core.util.SqlUtil;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.database.model.MediaMmsMessageRecord;
import org.thoughtcrime.securesms.database.model.MessageId;
@@ -32,12 +33,11 @@ import org.thoughtcrime.securesms.payments.State;
import org.thoughtcrime.securesms.payments.proto.PaymentMetaData;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.util.Base64;
import org.signal.core.util.CursorUtil;
import org.signal.core.util.SqlUtil;
import org.thoughtcrime.securesms.util.livedata.LiveDataUtil;
import org.whispersystems.signalservice.api.payments.Money;
import org.whispersystems.signalservice.api.util.UuidUtil;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
@@ -230,8 +230,8 @@ public final class PaymentTable extends DatabaseTable implements RecipientIdData
values.put(NOTE, note);
values.put(DIRECTION, direction.serialize());
values.put(STATE, state.serialize());
values.put(AMOUNT, CryptoValueUtil.moneyToCryptoValue(amount).toByteArray());
values.put(FEE, CryptoValueUtil.moneyToCryptoValue(fee).toByteArray());
values.put(AMOUNT, CryptoValueUtil.moneyToCryptoValue(amount).encode());
values.put(FEE, CryptoValueUtil.moneyToCryptoValue(fee).encode());
if (transaction != null) {
values.put(TRANSACTION, transaction);
} else {
@@ -245,9 +245,9 @@ public final class PaymentTable extends DatabaseTable implements RecipientIdData
values.putNull(PUBLIC_KEY);
}
if (metaData != null) {
values.put(META_DATA, metaData.toByteArray());
values.put(META_DATA, metaData.encode());
} else {
values.put(META_DATA, PaymentMetaDataUtil.fromReceiptAndTransaction(receipt, transaction).toByteArray());
values.put(META_DATA, PaymentMetaDataUtil.fromReceiptAndTransaction(receipt, transaction).encode());
}
values.put(SEEN, seen ? 1 : 0);
@@ -469,11 +469,11 @@ public final class PaymentTable extends DatabaseTable implements RecipientIdData
values.put(RECEIPT, receipt);
try {
values.put(PUBLIC_KEY, Base64.encodeBytes(PaymentMetaDataUtil.receiptPublic(PaymentMetaDataUtil.fromReceipt(receipt))));
values.put(META_DATA, PaymentMetaDataUtil.fromReceiptAndTransaction(receipt, transaction).toByteArray());
values.put(META_DATA, PaymentMetaDataUtil.fromReceiptAndTransaction(receipt, transaction).encode());
} catch (SerializationException e) {
throw new IllegalArgumentException(e);
}
values.put(FEE, CryptoValueUtil.moneyToCryptoValue(fee).toByteArray());
values.put(FEE, CryptoValueUtil.moneyToCryptoValue(fee).encode());
database.beginTransaction();
try {
@@ -526,7 +526,7 @@ public final class PaymentTable extends DatabaseTable implements RecipientIdData
values.put(STATE, state.serialize());
if (amount != null) {
values.put(AMOUNT, CryptoValueUtil.moneyToCryptoValue(amount).toByteArray());
values.put(AMOUNT, CryptoValueUtil.moneyToCryptoValue(amount).encode());
}
if (state == State.FAILED) {
@@ -623,9 +623,9 @@ public final class PaymentTable extends DatabaseTable implements RecipientIdData
private static @NonNull Money getMoneyValue(@NonNull byte[] blob) {
try {
CryptoValue cryptoValue = CryptoValue.parseFrom(blob);
CryptoValue cryptoValue = CryptoValue.ADAPTER.decode(blob);
return CryptoValueUtil.cryptoValueToMoney(cryptoValue);
} catch (InvalidProtocolBufferException e) {
} catch (IOException e) {
throw new AssertionError(e);
}
}

View File

@@ -9,8 +9,7 @@ import android.text.TextUtils
import androidx.annotation.VisibleForTesting
import androidx.core.content.contentValuesOf
import app.cash.exhaustive.Exhaustive
import com.google.protobuf.ByteString
import com.google.protobuf.InvalidProtocolBufferException
import okio.ByteString.Companion.toByteString
import org.signal.core.util.Bitmask
import org.signal.core.util.CursorUtil
import org.signal.core.util.SqlUtil
@@ -814,7 +813,7 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da
}
updateExtras(recipientId) {
it.setHideStory(insert.shouldHideStory())
it.hideStory(insert.shouldHideStory())
}
threadDatabase.applyStorageSyncUpdate(recipientId, insert)
@@ -871,7 +870,7 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da
}
updateExtras(recipientId) {
it.setHideStory(update.new.shouldHideStory())
it.hideStory(update.new.shouldHideStory())
}
threads.applyStorageSyncUpdate(recipientId, update.new)
@@ -910,8 +909,8 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da
Log.i(TAG, "Creating restore placeholder for $groupId")
val createdId = groups.create(
masterKey,
DecryptedGroup.newBuilder()
.setRevision(GroupsV2StateProcessor.RESTORE_PLACEHOLDER_REVISION)
DecryptedGroup.Builder()
.revision(GroupsV2StateProcessor.RESTORE_PLACEHOLDER_REVISION)
.build()
)
@@ -921,7 +920,7 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da
groups.setShowAsStoryState(groupId, insert.storySendMode.toShowAsStoryState())
updateExtras(recipient.id) {
it.setHideStory(insert.shouldHideStory())
it.hideStory(insert.shouldHideStory())
}
Log.i(TAG, "Scheduling request for latest group info for $groupId")
@@ -943,7 +942,7 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da
val recipient = Recipient.externalGroupExact(groupId)
updateExtras(recipient.id) {
it.setHideStory(update.new.shouldHideStory())
it.hideStory(update.new.shouldHideStory())
}
groups.setShowAsStoryState(groupId, update.new.storySendMode.toShowAsStoryState())
@@ -1222,7 +1221,7 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da
Log.d(TAG, "No recipients utilizing updated chat color.")
} else {
val values = ContentValues(2).apply {
put(CHAT_COLORS, chatColors.serialize().toByteArray())
put(CHAT_COLORS, chatColors.serialize().encode())
put(CUSTOM_CHAT_COLORS_ID, chatColors.id.longValue)
}
@@ -1313,7 +1312,7 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da
fun setColor(id: RecipientId, color: ChatColors) {
val values = ContentValues().apply {
put(CHAT_COLORS, color.serialize().toByteArray())
put(CHAT_COLORS, color.serialize().encode())
put(CUSTOM_CHAT_COLORS_ID, color.id.longValue)
}
if (update(id, values)) {
@@ -1427,7 +1426,7 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da
fun setLastSessionResetTime(id: RecipientId, lastResetTime: DeviceLastResetTime) {
val values = ContentValues(1).apply {
put(LAST_SESSION_RESET, lastResetTime.toByteArray())
put(LAST_SESSION_RESET, lastResetTime.encode())
}
update(id, values)
}
@@ -1438,28 +1437,25 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da
return try {
val serialized = cursor.requireBlob(LAST_SESSION_RESET)
if (serialized != null) {
DeviceLastResetTime.parseFrom(serialized)
DeviceLastResetTime.ADAPTER.decode(serialized)
} else {
DeviceLastResetTime.newBuilder().build()
DeviceLastResetTime()
}
} catch (e: InvalidProtocolBufferException) {
} catch (e: IOException) {
Log.w(TAG, e)
DeviceLastResetTime.newBuilder().build()
DeviceLastResetTime()
}
}
}
return DeviceLastResetTime.newBuilder().build()
return DeviceLastResetTime()
}
fun setBadges(id: RecipientId, badges: List<Badge>) {
val badgeListBuilder = BadgeList.newBuilder()
for (badge in badges) {
badgeListBuilder.addBadges(toDatabaseBadge(badge))
}
val badgeList = BadgeList(badges = badges.map { toDatabaseBadge(it) })
val values = ContentValues(1).apply {
put(BADGES, badgeListBuilder.build().toByteArray())
put(BADGES, badgeList.encode())
}
if (update(id, values)) {
@@ -1568,12 +1564,12 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da
): Boolean {
val selection = "$ID = ? AND $PROFILE_KEY = ?"
val args = arrayOf(id.serialize(), Base64.encodeBytes(profileKey.serialize()))
val columnData = ExpiringProfileKeyCredentialColumnData.newBuilder()
.setProfileKey(ByteString.copyFrom(profileKey.serialize()))
.setExpiringProfileKeyCredential(ByteString.copyFrom(expiringProfileKeyCredential.serialize()))
val columnData = ExpiringProfileKeyCredentialColumnData.Builder()
.profileKey(profileKey.serialize().toByteString())
.expiringProfileKeyCredential(expiringProfileKeyCredential.serialize().toByteString())
.build()
val values = ContentValues(1).apply {
put(EXPIRING_PROFILE_KEY_CREDENTIAL, Base64.encodeBytes(columnData.toByteArray()))
put(EXPIRING_PROFILE_KEY_CREDENTIAL, Base64.encodeBytes(columnData.encode()))
}
val updateQuery = SqlUtil.buildTrueUpdateQuery(selection, args, values)
@@ -1850,9 +1846,9 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da
private fun setWallpaper(id: RecipientId, wallpaper: Wallpaper?) {
val existingWallpaperUri = getWallpaperUri(id)
val values = ContentValues().apply {
put(WALLPAPER, wallpaper?.toByteArray())
if (wallpaper != null && wallpaper.hasFile()) {
put(WALLPAPER_URI, wallpaper.file.uri)
put(WALLPAPER, wallpaper?.encode())
if (wallpaper?.file_ != null) {
put(WALLPAPER_URI, wallpaper.file_.uri)
} else {
putNull(WALLPAPER_URI)
}
@@ -1869,8 +1865,8 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da
fun setDimWallpaperInDarkTheme(id: RecipientId, enabled: Boolean) {
val wallpaper = getWallpaper(id) ?: throw IllegalStateException("No wallpaper set for $id")
val updated = wallpaper.toBuilder()
.setDimLevelInDarkTheme(if (enabled) ChatWallpaper.FIXED_DIM_LEVEL_FOR_DARK_THEME else 0f)
val updated = wallpaper.newBuilder()
.dimLevelInDarkTheme(if (enabled) ChatWallpaper.FIXED_DIM_LEVEL_FOR_DARK_THEME else 0f)
.build()
setWallpaper(id, updated)
@@ -1882,8 +1878,8 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da
val raw = cursor.requireBlob(WALLPAPER)
return if (raw != null) {
try {
Wallpaper.parseFrom(raw)
} catch (e: InvalidProtocolBufferException) {
Wallpaper.ADAPTER.decode(raw)
} catch (e: IOException) {
null
}
} else {
@@ -1898,8 +1894,8 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da
private fun getWallpaperUri(id: RecipientId): Uri? {
val wallpaper = getWallpaper(id)
return if (wallpaper != null && wallpaper.hasFile()) {
Uri.parse(wallpaper.file.uri)
return if (wallpaper != null && wallpaper.file_ != null) {
Uri.parse(wallpaper.file_.uri)
} else {
null
}
@@ -2046,13 +2042,13 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da
}
fun setHideStory(id: RecipientId, hideStory: Boolean) {
updateExtras(id) { it.setHideStory(hideStory) }
updateExtras(id) { it.hideStory(hideStory) }
rotateStorageId(id)
StorageSyncHelper.scheduleSyncForDataChange()
}
fun updateLastStoryViewTimestamp(id: RecipientId) {
updateExtras(id) { it.setLastStoryView(System.currentTimeMillis()) }
updateExtras(id) { it.lastStoryView(System.currentTimeMillis()) }
}
fun clearUsernameIfExists(username: String) {
@@ -2329,10 +2325,12 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da
is PnpOperation.SetPni -> {
affectedIds.add(operation.recipientId)
}
is PnpOperation.Merge -> {
oldIds.add(operation.secondaryId)
affectedIds.add(operation.primaryId)
}
is PnpOperation.SessionSwitchoverInsert -> {}
is PnpOperation.ChangeNumberInsert -> changedNumberId = operation.recipientId
}
@@ -2364,6 +2362,7 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da
.where("$ID = ?", operation.recipientId)
.run()
}
is PnpOperation.RemovePni -> {
writableDatabase
.update(TABLE_NAME)
@@ -2371,6 +2370,7 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da
.where("$ID = ?", operation.recipientId)
.run()
}
is PnpOperation.SetAci -> {
writableDatabase
.update(TABLE_NAME)
@@ -2382,6 +2382,7 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da
.where("$ID = ?", operation.recipientId)
.run()
}
is PnpOperation.SetE164 -> {
writableDatabase
.update(TABLE_NAME)
@@ -2389,6 +2390,7 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da
.where("$ID = ?", operation.recipientId)
.run()
}
is PnpOperation.SetPni -> {
writableDatabase
.update(TABLE_NAME)
@@ -2406,20 +2408,19 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da
.where("$ID = ?", operation.recipientId)
.run()
}
is PnpOperation.Merge -> {
val mergeResult: MergeResult = merge(operation.primaryId, operation.secondaryId, inputPni)
hadThreadMerge = hadThreadMerge || mergeResult.neededThreadMerge
}
is PnpOperation.SessionSwitchoverInsert -> {
if (hadThreadMerge) {
Log.d(TAG, "Skipping SSE insert because we already had a thread merge event.")
} else {
val threadId: Long? = threads.getThreadIdFor(operation.recipientId)
if (threadId != null) {
val event = SessionSwitchoverEvent
.newBuilder()
.setE164(operation.e164 ?: "")
.build()
val event = SessionSwitchoverEvent(e164 = operation.e164 ?: "")
try {
SignalDatabase.messages.insertSessionSwitchoverEvent(operation.recipientId, threadId, event)
} catch (e: Exception) {
@@ -2471,6 +2472,7 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da
}
}
}
is PnpOperation.ChangeNumberInsert -> {
if (changeSet.id is PnpIdResolver.PnpNoopId) {
SignalDatabase.messages.insertNumberChangeMessages(changeSet.id.recipientId)
@@ -2485,6 +2487,7 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da
is PnpIdResolver.PnpNoopId -> {
changeSet.id.recipientId
}
is PnpIdResolver.PnpInsert -> {
val id: Long = writableDatabase.insert(TABLE_NAME, null, buildContentValuesForNewUser(changeSet.id.e164, changeSet.id.pni, changeSet.id.aci))
RecipientId.from(id)
@@ -3094,8 +3097,8 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da
val serializedChatColors = cursor.requireBlob(CHAT_COLORS)
var chatColors: ChatColors? = if (serializedChatColors != null) {
try {
forChatColor(forLongValue(customChatColorsId), ChatColor.parseFrom(serializedChatColors))
} catch (e: InvalidProtocolBufferException) {
forChatColor(forLongValue(customChatColorsId), ChatColor.ADAPTER.decode(serializedChatColors))
} catch (e: IOException) {
null
}
} else {
@@ -3117,7 +3120,7 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da
}
val contentValues = ContentValues().apply {
put(CHAT_COLORS, chatColors.serialize().toByteArray())
put(CHAT_COLORS, chatColors.serialize().encode())
put(CUSTOM_CHAT_COLORS_ID, chatColors.id.longValue)
}
db.update(TABLE_NAME, contentValues, "$ID = ?", arrayOf(id.toString()))
@@ -3604,7 +3607,7 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da
}
fun manuallyShowAvatar(recipientId: RecipientId) {
updateExtras(recipientId) { b: RecipientExtras.Builder -> b.setManuallyShownAvatar(true) }
updateExtras(recipientId) { b: RecipientExtras.Builder -> b.manuallyShownAvatar(true) }
}
fun getCapabilities(id: RecipientId): RecipientRecord.Capabilities? {
@@ -3629,8 +3632,8 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da
db.query(TABLE_NAME, arrayOf(ID, EXTRAS), ID_WHERE, SqlUtil.buildArgs(recipientId), null, null, null).use { cursor ->
if (cursor.moveToNext()) {
val state = getRecipientExtras(cursor)
val builder = if (state != null) state.toBuilder() else RecipientExtras.newBuilder()
val updatedState = updater.apply(builder).build().toByteArray()
val builder = state?.newBuilder() ?: RecipientExtras.Builder()
val updatedState = updater.apply(builder).build().encode()
val values = ContentValues(1).apply {
put(EXTRAS, updatedState)
}
@@ -3782,7 +3785,7 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da
// Thread Merge Event (remaps happen inside ThreadTable#merge)
if (threadMerge.neededMerge) {
val mergeEvent: ThreadMergeEvent.Builder = ThreadMergeEvent.newBuilder()
val mergeEvent: ThreadMergeEvent.Builder = ThreadMergeEvent.Builder()
if (secondaryRecord.e164 != null) {
mergeEvent.previousE164 = secondaryRecord.e164
@@ -3807,7 +3810,7 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da
CALL_VIBRATE to if (primaryRecord.callVibrateState != VibrateState.DEFAULT) primaryRecord.callVibrateState.id else secondaryRecord.callVibrateState.id,
NOTIFICATION_CHANNEL to (primaryRecord.notificationChannel ?: secondaryRecord.notificationChannel),
MUTE_UNTIL to if (primaryRecord.muteUntil > 0) primaryRecord.muteUntil else secondaryRecord.muteUntil,
CHAT_COLORS to Optional.ofNullable(primaryRecord.chatColors).or(Optional.ofNullable(secondaryRecord.chatColors)).map { colors: ChatColors? -> colors!!.serialize().toByteArray() }.orElse(null),
CHAT_COLORS to Optional.ofNullable(primaryRecord.chatColors).or(Optional.ofNullable(secondaryRecord.chatColors)).map { colors: ChatColors? -> colors!!.serialize().encode() }.orElse(null),
AVATAR_COLOR to primaryRecord.avatarColor.serialize(),
CUSTOM_CHAT_COLORS_ID to Optional.ofNullable(primaryRecord.chatColors).or(Optional.ofNullable(secondaryRecord.chatColors)).map { colors: ChatColors? -> colors!!.id.longValue }.orElse(null),
MESSAGE_EXPIRATION_TIME to if (primaryRecord.expireMessages > 0) primaryRecord.expireMessages else secondaryRecord.expireMessages,
@@ -4094,7 +4097,7 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da
if (expiringProfileKeyCredentialString != null) {
try {
val columnDataBytes = Base64.decode(expiringProfileKeyCredentialString)
val columnData = ExpiringProfileKeyCredentialColumnData.parseFrom(columnDataBytes)
val columnData = ExpiringProfileKeyCredentialColumnData.ADAPTER.decode(columnDataBytes)
if (Arrays.equals(columnData.profileKey.toByteArray(), profileKey)) {
expiringProfileKeyCredential = ExpiringProfileKeyCredential(columnData.expiringProfileKeyCredential.toByteArray())
} else {
@@ -4111,8 +4114,8 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da
val serializedWallpaper = cursor.requireBlob(WALLPAPER)
val chatWallpaper: ChatWallpaper? = if (serializedWallpaper != null) {
try {
ChatWallpaperFactory.create(Wallpaper.parseFrom(serializedWallpaper))
} catch (e: InvalidProtocolBufferException) {
ChatWallpaperFactory.create(Wallpaper.ADAPTER.decode(serializedWallpaper))
} catch (e: IOException) {
Log.w(TAG, "Failed to parse wallpaper.", e)
null
}
@@ -4124,8 +4127,8 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da
val serializedChatColors = cursor.requireBlob(CHAT_COLORS)
val chatColors: ChatColors? = if (serializedChatColors != null) {
try {
forChatColor(forLongValue(customChatColorsId), ChatColor.parseFrom(serializedChatColors))
} catch (e: InvalidProtocolBufferException) {
forChatColor(forLongValue(customChatColorsId), ChatColor.ADAPTER.decode(serializedChatColors))
} catch (e: IOException) {
Log.w(TAG, "Failed to parse chat colors.", e)
null
}
@@ -4206,15 +4209,15 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da
var badgeList: BadgeList? = null
if (serializedBadgeList != null) {
try {
badgeList = BadgeList.parseFrom(serializedBadgeList)
} catch (e: InvalidProtocolBufferException) {
badgeList = BadgeList.ADAPTER.decode(serializedBadgeList)
} catch (e: IOException) {
Log.w(TAG, e)
}
}
val badges: List<Badge>
if (badgeList != null) {
val protoBadges = badgeList.badgesList
val protoBadges = badgeList.badges
badges = ArrayList(protoBadges.size)
for (protoBadge in protoBadges) {
badges.add(Badges.fromDatabaseBadge(protoBadge))
@@ -4254,10 +4257,10 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da
}
private fun getRecipientExtras(cursor: Cursor): RecipientExtras? {
return cursor.optionalBlob(EXTRAS).map { b: ByteArray? ->
return cursor.optionalBlob(EXTRAS).map { b: ByteArray ->
try {
RecipientExtras.parseFrom(b)
} catch (e: InvalidProtocolBufferException) {
RecipientExtras.ADAPTER.decode(b)
} catch (e: IOException) {
Log.w(TAG, e)
throw AssertionError(e)
}

View File

@@ -7,7 +7,7 @@ import org.whispersystems.signalservice.api.messages.SignalServiceStoryMessageRe
import org.whispersystems.signalservice.api.push.DistributionId
import org.whispersystems.signalservice.api.push.ServiceId
import org.whispersystems.signalservice.api.push.SignalServiceAddress
import org.whispersystems.signalservice.internal.push.SignalServiceProtos
import org.whispersystems.signalservice.internal.push.SyncMessage
/**
* Represents a list of, or update to a list of, who can access a story through what
@@ -84,12 +84,12 @@ data class SentStorySyncManifest(
return SentStorySyncManifest(entries)
}
fun fromRecipientsSet(recipients: List<SignalServiceProtos.SyncMessage.Sent.StoryMessageRecipient>): SentStorySyncManifest {
fun fromRecipientsSet(recipients: List<SyncMessage.Sent.StoryMessageRecipient>): SentStorySyncManifest {
val entries = recipients.toSet().map { recipient ->
Entry(
recipientId = RecipientId.from(ServiceId.parseOrThrow(recipient.destinationServiceId)),
allowedToReply = recipient.isAllowedToReply,
distributionLists = recipient.distributionListIdsList.map { DistributionId.from(it) }
recipientId = RecipientId.from(ServiceId.parseOrThrow(recipient.destinationServiceId!!)),
allowedToReply = recipient.isAllowedToReply!!,
distributionLists = recipient.distributionListIds.map { DistributionId.from(it) }
)
}

View File

@@ -14,7 +14,6 @@ import android.preference.PreferenceManager
import android.text.TextUtils
import androidx.core.content.contentValuesOf
import com.annimon.stream.Stream
import com.google.protobuf.InvalidProtocolBufferException
import net.zetetic.database.sqlcipher.SQLiteDatabase
import org.signal.core.util.CursorUtil
import org.signal.core.util.Hex
@@ -50,6 +49,7 @@ import org.thoughtcrime.securesms.util.Util
import org.whispersystems.signalservice.api.push.DistributionId
import org.whispersystems.signalservice.api.push.ServiceId.ACI
import java.io.File
import java.io.IOException
import java.util.LinkedList
import java.util.Locale
import java.util.UUID
@@ -1375,14 +1375,14 @@ object V149_LegacyMigrations : SignalDatabaseMigration {
continue
}
try {
val hasReceiveLaterThanNotified: Boolean = ReactionList.parseFrom(reactions)
.reactionsList
val hasReceiveLaterThanNotified: Boolean = ReactionList.ADAPTER.decode(reactions)
.reactions
.stream()
.anyMatch { r: ReactionList.Reaction -> r.receivedTime > notifiedTimestamp }
if (!hasReceiveLaterThanNotified) {
smsIds.add(cursor.getLong(cursor.getColumnIndexOrThrow("_id")))
}
} catch (e: InvalidProtocolBufferException) {
} catch (e: IOException) {
Log.e(TAG, e)
}
}
@@ -1402,14 +1402,14 @@ object V149_LegacyMigrations : SignalDatabaseMigration {
continue
}
try {
val hasReceiveLaterThanNotified: Boolean = ReactionList.parseFrom(reactions)
.reactionsList
val hasReceiveLaterThanNotified: Boolean = ReactionList.ADAPTER.decode(reactions)
.reactions
.stream()
.anyMatch { r: ReactionList.Reaction -> r.receivedTime > notifiedTimestamp }
if (!hasReceiveLaterThanNotified) {
mmsIds.add(cursor.getLong(cursor.getColumnIndexOrThrow("_id")))
}
} catch (e: InvalidProtocolBufferException) {
} catch (e: IOException) {
Log.e(TAG, e)
}
}
@@ -1490,7 +1490,7 @@ object V149_LegacyMigrations : SignalDatabaseMigration {
for (entry: Map.Entry<MaterialColor, ChatColors> in entrySet) {
val whereArgs = SqlUtil.buildArgs(entry.key.serialize())
val values = ContentValues(2)
values.put("chat_colors", entry.value.serialize().toByteArray())
values.put("chat_colors", entry.value.serialize().encode())
values.put("custom_chat_colors_id", entry.value.id.longValue)
db.update("recipient", values, where, whereArgs)
}
@@ -2678,9 +2678,9 @@ object V149_LegacyMigrations : SignalDatabaseMigration {
private fun migrateReaction(db: SQLiteDatabase, cursor: Cursor, isMms: Boolean) {
try {
val messageId = CursorUtil.requireLong(cursor, "_id")
val reactionList = ReactionList.parseFrom(CursorUtil.requireBlob(cursor, "reactions"))
val reactionList = ReactionList.ADAPTER.decode(CursorUtil.requireBlob(cursor, "reactions"))
for (reaction in reactionList.reactionsList) {
for (reaction in reactionList.reactions) {
val contentValues = ContentValues().apply {
put("message_id", messageId)
put("is_mms", if (isMms) 1 else 0)
@@ -2691,7 +2691,7 @@ object V149_LegacyMigrations : SignalDatabaseMigration {
}
db.insert("reaction", null, contentValues)
}
} catch (e: InvalidProtocolBufferException) {
} catch (e: IOException) {
Log.w(TAG, "Failed to parse reaction!")
}
}

View File

@@ -69,7 +69,7 @@ class AvatarPickerDatabase(context: Context, databaseHelper: SignalDatabase) : D
val where = ID_WHERE
val values = ContentValues(1)
values.put(AVATAR, avatar.toProto().toByteArray())
values.put(AVATAR, avatar.toProto().encode())
db.update(TABLE_NAME, values, where, SqlUtil.buildArgs(databaseId.id))
}
@@ -96,14 +96,14 @@ class AvatarPickerDatabase(context: Context, databaseHelper: SignalDatabase) : D
if (databaseId is Avatar.DatabaseId.Saved) {
val values = ContentValues(2)
values.put(AVATAR, avatar.toProto().toByteArray())
values.put(AVATAR, avatar.toProto().encode())
db.update(TABLE_NAME, values, ID_WHERE, SqlUtil.buildArgs(databaseId.id))
return avatar
} else {
val values = ContentValues(4)
values.put(AVATAR, avatar.toProto().toByteArray())
values.put(AVATAR, avatar.toProto().encode())
if (groupId != null) {
values.put(GROUP_ID, groupId.toString())
@@ -126,7 +126,7 @@ class AvatarPickerDatabase(context: Context, databaseHelper: SignalDatabase) : D
while (it.moveToNext()) {
val id = CursorUtil.requireLong(it, ID)
val blob = CursorUtil.requireBlob(it, AVATAR)
val proto = CustomAvatar.parseFrom(blob)
val proto = CustomAvatar.ADAPTER.decode(blob)
results.add(proto.toAvatar(id))
}
}
@@ -157,7 +157,7 @@ class AvatarPickerDatabase(context: Context, databaseHelper: SignalDatabase) : D
while (it.moveToNext()) {
val id = CursorUtil.requireLong(it, ID)
val blob = CursorUtil.requireBlob(it, AVATAR)
val proto = CustomAvatar.parseFrom(blob)
val proto = CustomAvatar.ADAPTER.decode(blob)
results.add(proto.toAvatar(id))
}
}
@@ -167,18 +167,18 @@ class AvatarPickerDatabase(context: Context, databaseHelper: SignalDatabase) : D
private fun Avatar.toProto(): CustomAvatar {
return when (this) {
is Avatar.Photo -> CustomAvatar.newBuilder().setPhoto(CustomAvatar.Photo.newBuilder().setUri(this.uri.toString())).build()
is Avatar.Text -> CustomAvatar.newBuilder().setText(CustomAvatar.Text.newBuilder().setText(this.text).setColors(this.color.code)).build()
is Avatar.Vector -> CustomAvatar.newBuilder().setVector(CustomAvatar.Vector.newBuilder().setKey(this.key).setColors(this.color.code)).build()
is Avatar.Photo -> CustomAvatar(photo = CustomAvatar.Photo(uri = this.uri.toString()))
is Avatar.Text -> CustomAvatar(text = CustomAvatar.Text(text = this.text, colors = this.color.code))
is Avatar.Vector -> CustomAvatar(vector = CustomAvatar.Vector(key = this.key, colors = this.color.code))
else -> throw AssertionError()
}
}
private fun CustomAvatar.toAvatar(id: Long): Avatar {
return when {
hasPhoto() -> Avatar.Photo(Uri.parse(photo.uri), photo.size, Avatar.DatabaseId.Saved(id))
hasText() -> Avatar.Text(text.text, Avatars.colorMap[text.colors] ?: Avatars.colors[0], Avatar.DatabaseId.Saved(id))
hasVector() -> Avatar.Vector(vector.key, Avatars.colorMap[vector.colors] ?: Avatars.colors[0], Avatar.DatabaseId.Saved(id))
photo != null -> Avatar.Photo(Uri.parse(photo.uri), photo.size, Avatar.DatabaseId.Saved(id))
text != null -> Avatar.Text(text.text, Avatars.colorMap[text.colors] ?: Avatars.colors[0], Avatar.DatabaseId.Saved(id))
vector != null -> Avatar.Vector(vector.key, Avatars.colorMap[vector.colors] ?: Avatars.colors[0], Avatar.DatabaseId.Saved(id))
else -> throw AssertionError()
}
}

View File

@@ -5,8 +5,8 @@ import org.thoughtcrime.securesms.database.model.databaseprotos.BodyRangeList
import org.thoughtcrime.securesms.util.Base64
object BodyRangeListSerializer : StringSerializer<BodyRangeList> {
override fun serialize(data: BodyRangeList): String = Base64.encodeBytes(data.toByteArray())
override fun deserialize(data: String): BodyRangeList = BodyRangeList.parseFrom(Base64.decode(data))
override fun serialize(data: BodyRangeList): String = Base64.encodeBytes(data.encode())
override fun deserialize(data: String): BodyRangeList = BodyRangeList.ADAPTER.decode(Base64.decode(data))
}
fun BodyRangeList.serialize(): String {

View File

@@ -2,46 +2,27 @@
package org.thoughtcrime.securesms.database.model
import com.google.protobuf.ByteString
import org.thoughtcrime.securesms.database.model.databaseprotos.BodyRangeList
import org.whispersystems.signalservice.internal.push.SignalServiceProtos.BodyRange
import org.whispersystems.signalservice.internal.push.BodyRange
/**
* Collection of extensions to make working with database protos cleaner.
*/
fun ByteArray.toProtoByteString(): ByteString {
return ByteString.copyFrom(this)
}
fun BodyRangeList.Builder.addStyle(style: BodyRangeList.BodyRange.Style, start: Int, length: Int): BodyRangeList.Builder {
addRanges(
BodyRangeList.BodyRange.newBuilder()
.setStyle(style)
.setStart(start)
.setLength(length)
)
ranges += BodyRangeList.BodyRange(style = style, start = start, length = length)
return this
}
fun BodyRangeList.Builder.addLink(link: String, start: Int, length: Int): BodyRangeList.Builder {
addRanges(
BodyRangeList.BodyRange.newBuilder()
.setLink(link)
.setStart(start)
.setLength(length)
)
ranges += BodyRangeList.BodyRange(link = link, start = start, length = length)
return this
}
fun BodyRangeList.Builder.addButton(label: String, action: String, start: Int, length: Int): BodyRangeList.Builder {
addRanges(
BodyRangeList.BodyRange.newBuilder()
.setButton(BodyRangeList.BodyRange.Button.newBuilder().setLabel(label).setAction(action))
.setStart(start)
.setLength(length)
ranges += BodyRangeList.BodyRange(
button = BodyRangeList.BodyRange.Button(label = label, action = action),
start = start,
length = length
)
return this
@@ -52,7 +33,7 @@ fun List<BodyRange>?.toBodyRangeList(): BodyRangeList? {
return null
}
val builder = BodyRangeList.newBuilder()
val builder = BodyRangeList.Builder()
for (bodyRange in this) {
var style: BodyRangeList.BodyRange.Style? = null
@@ -65,7 +46,7 @@ fun List<BodyRange>?.toBodyRangeList(): BodyRangeList? {
else -> Unit
}
if (style != null) {
builder.addStyle(style, bodyRange.start, bodyRange.length)
builder.addStyle(style, bodyRange.start!!, bodyRange.length!!)
}
}

View File

@@ -6,7 +6,6 @@ import androidx.annotation.Nullable;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.database.model.databaseprotos.GroupCallUpdateDetails;
import org.thoughtcrime.securesms.util.Base64;
import org.thoughtcrime.securesms.util.Util;
import java.io.IOException;
import java.util.List;
@@ -19,14 +18,14 @@ public final class GroupCallUpdateDetailsUtil {
}
public static @NonNull GroupCallUpdateDetails parse(@Nullable String body) {
GroupCallUpdateDetails groupCallUpdateDetails = GroupCallUpdateDetails.getDefaultInstance();
GroupCallUpdateDetails groupCallUpdateDetails = new GroupCallUpdateDetails();
if (body == null) {
return groupCallUpdateDetails;
}
try {
groupCallUpdateDetails = GroupCallUpdateDetails.parseFrom(Base64.decode(body));
groupCallUpdateDetails = GroupCallUpdateDetails.ADAPTER.decode(Base64.decode(body));
} catch (IOException e) {
Log.w(TAG, "Group call update details could not be read", e);
}
@@ -35,14 +34,10 @@ public final class GroupCallUpdateDetailsUtil {
}
public static @NonNull String createUpdatedBody(@NonNull GroupCallUpdateDetails groupCallUpdateDetails, @NonNull List<String> inCallUuids, boolean isCallFull) {
GroupCallUpdateDetails.Builder builder = groupCallUpdateDetails.toBuilder()
.setIsCallFull(isCallFull)
.clearInCallUuids();
GroupCallUpdateDetails.Builder builder = groupCallUpdateDetails.newBuilder()
.isCallFull(isCallFull)
.inCallUuids(inCallUuids);
if (Util.hasItems(inCallUuids)) {
builder.addAllInCallUuids(inCallUuids);
}
return Base64.encodeBytes(builder.build().toByteArray());
return Base64.encodeBytes(builder.build().encode());
}
}

View File

@@ -12,8 +12,8 @@ import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.util.DateUtils;
import org.whispersystems.signalservice.api.push.ServiceId.ACI;
import org.whispersystems.signalservice.api.push.ServiceId;
import org.whispersystems.signalservice.api.push.ServiceId.ACI;
import java.util.ArrayList;
import java.util.List;
@@ -53,14 +53,14 @@ public class GroupCallUpdateMessageFactory implements UpdateDescription.Spannabl
}
private @NonNull String createString() {
String time = DateUtils.getTimeString(context, Locale.getDefault(), groupCallUpdateDetails.getStartedCallTimestamp());
String time = DateUtils.getTimeString(context, Locale.getDefault(), groupCallUpdateDetails.startedCallTimestamp);
switch (joinedMembers.size()) {
case 0:
return withTime ? context.getString(R.string.MessageRecord_group_call_s, time)
: context.getString(R.string.MessageRecord_group_call);
case 1:
if (joinedMembers.get(0).toString().equals(groupCallUpdateDetails.getStartedCallUuid())) {
if (joinedMembers.get(0).toString().equals(groupCallUpdateDetails.startedCallUuid)) {
if (Objects.equals(joinedMembers.get(0), selfAci)) {
return withTime ? context.getString(R.string.MessageRecord_you_started_a_group_call_s, time)
: context.getString(R.string.MessageRecord_you_started_a_group_call);

View File

@@ -87,7 +87,7 @@ class GroupRecord(
val membershipAdditionAccessControl: GroupAccessControl
get() {
return if (isV2Group) {
if (requireV2GroupProperties().decryptedGroup.accessControl.members == AccessControl.AccessRequired.MEMBER) {
if (requireV2GroupProperties().decryptedGroup.accessControl!!.members == AccessControl.AccessRequired.MEMBER) {
GroupAccessControl.ALL_MEMBERS
} else {
GroupAccessControl.ONLY_ADMINS
@@ -105,7 +105,7 @@ class GroupRecord(
val attributesAccessControl: GroupAccessControl
get() {
return if (isV2Group) {
if (requireV2GroupProperties().decryptedGroup.accessControl.attributes == AccessControl.AccessRequired.MEMBER) {
if (requireV2GroupProperties().decryptedGroup.accessControl!!.attributes == AccessControl.AccessRequired.MEMBER) {
GroupAccessControl.ALL_MEMBERS
} else {
GroupAccessControl.ONLY_ADMINS
@@ -121,7 +121,7 @@ class GroupRecord(
if (isV2Group && memberLevel(Recipient.self()) == GroupTable.MemberLevel.ADMINISTRATOR) {
requireV2GroupProperties()
.decryptedGroup
.requestingMembersCount
.requestingMembers.size
} else {
0
}
@@ -175,7 +175,7 @@ class GroupRecord(
if (isV2Group) {
val serviceId = recipient.serviceId
if (serviceId.isPresent) {
return DecryptedGroupUtil.findPendingByServiceId(requireV2GroupProperties().decryptedGroup.pendingMembersList, serviceId.get())
return DecryptedGroupUtil.findPendingByServiceId(requireV2GroupProperties().decryptedGroup.pendingMembers, serviceId.get())
.isPresent
}
}

View File

@@ -12,8 +12,6 @@ import androidx.annotation.StringRes;
import androidx.annotation.VisibleForTesting;
import androidx.core.content.ContextCompat;
import com.google.protobuf.ByteString;
import org.signal.core.util.StringUtil;
import org.signal.storageservice.protos.groups.AccessControl;
import org.signal.storageservice.protos.groups.Member;
@@ -51,6 +49,8 @@ import java.util.UUID;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import okio.ByteString;
final class GroupsV2UpdateMessageProducer {
@NonNull private final Context context;
@@ -72,26 +72,32 @@ final class GroupsV2UpdateMessageProducer {
* <p>
* When the revision of the group is 0, the change is very noisy and only the editor is useful.
*/
UpdateDescription describeNewGroup(@NonNull DecryptedGroup group, @NonNull DecryptedGroupChange decryptedGroupChange) {
Optional<DecryptedPendingMember> selfPending = DecryptedGroupUtil.findPendingByServiceId(group.getPendingMembersList(), selfIds.getAci());
if (!selfPending.isPresent() && selfIds.getPni() != null) {
selfPending = DecryptedGroupUtil.findPendingByServiceId(group.getPendingMembersList(), selfIds.getPni());
}
UpdateDescription describeNewGroup(@Nullable DecryptedGroup group, @Nullable DecryptedGroupChange decryptedGroupChange) {
Optional<DecryptedPendingMember> selfPending = Optional.empty();
if (selfPending.isPresent()) {
return updateDescription(R.string.MessageRecord_s_invited_you_to_the_group, selfPending.get().getAddedByAci(), R.drawable.ic_update_group_add_16);
}
ByteString foundingMemberUuid = decryptedGroupChange.getEditorServiceIdBytes();
if (!foundingMemberUuid.isEmpty()) {
if (selfIds.matches(foundingMemberUuid)) {
return updateDescription(context.getString(R.string.MessageRecord_you_created_the_group), R.drawable.ic_update_group_16);
} else {
return updateDescription(R.string.MessageRecord_s_added_you, foundingMemberUuid, R.drawable.ic_update_group_add_16);
if (group != null) {
selfPending = DecryptedGroupUtil.findPendingByServiceId(group.pendingMembers, selfIds.getAci());
if (selfPending.isEmpty() && selfIds.getPni() != null) {
selfPending = DecryptedGroupUtil.findPendingByServiceId(group.pendingMembers, selfIds.getPni());
}
}
if (DecryptedGroupUtil.findMemberByAci(group.getMembersList(), selfIds.getAci()).isPresent()) {
if (selfPending.isPresent()) {
return updateDescription(R.string.MessageRecord_s_invited_you_to_the_group, selfPending.get().addedByAci, R.drawable.ic_update_group_add_16);
}
if (decryptedGroupChange != null) {
ByteString foundingMemberUuid = decryptedGroupChange.editorServiceIdBytes;
if (foundingMemberUuid.size() > 0) {
if (selfIds.matches(foundingMemberUuid)) {
return updateDescription(context.getString(R.string.MessageRecord_you_created_the_group), R.drawable.ic_update_group_16);
} else {
return updateDescription(R.string.MessageRecord_s_added_you, foundingMemberUuid, R.drawable.ic_update_group_add_16);
}
}
}
if (group != null && DecryptedGroupUtil.findMemberByAci(group.members, selfIds.getAci()).isPresent()) {
return updateDescription(context.getString(R.string.MessageRecord_you_joined_the_group), R.drawable.ic_update_group_add_16);
} else {
return updateDescription(context.getString(R.string.MessageRecord_group_updated), R.drawable.ic_update_group_16);
@@ -99,14 +105,14 @@ final class GroupsV2UpdateMessageProducer {
}
List<UpdateDescription> describeChanges(@Nullable DecryptedGroup previousGroupState, @NonNull DecryptedGroupChange change) {
if (DecryptedGroup.getDefaultInstance().equals(previousGroupState)) {
if (new DecryptedGroup().equals(previousGroupState)) {
previousGroupState = null;
}
List<UpdateDescription> updates = new LinkedList<>();
boolean editorUnknown = change.getEditorServiceIdBytes().isEmpty();
ServiceId editorServiceId = editorUnknown ? null : ServiceId.parseOrNull(change.getEditorServiceIdBytes());
boolean editorUnknown = change.editorServiceIdBytes.size() == 0;
ServiceId editorServiceId = editorUnknown ? null : ServiceId.parseOrNull(change.editorServiceIdBytes);
if (editorServiceId == null || editorServiceId.isUnknown()) {
editorUnknown = true;
@@ -172,12 +178,12 @@ final class GroupsV2UpdateMessageProducer {
* Handles case of future protocol versions where we don't know what has changed.
*/
private void describeUnknownChange(@NonNull DecryptedGroupChange change, @NonNull List<UpdateDescription> updates) {
boolean editorIsYou = selfIds.matches(change.getEditorServiceIdBytes());
boolean editorIsYou = selfIds.matches(change.editorServiceIdBytes);
if (editorIsYou) {
updates.add(updateDescription(context.getString(R.string.MessageRecord_you_updated_group), R.drawable.ic_update_group_16));
} else {
updates.add(updateDescription(R.string.MessageRecord_s_updated_group, change.getEditorServiceIdBytes(), R.drawable.ic_update_group_16));
updates.add(updateDescription(R.string.MessageRecord_s_updated_group, change.editorServiceIdBytes, R.drawable.ic_update_group_16));
}
}
@@ -186,25 +192,25 @@ final class GroupsV2UpdateMessageProducer {
}
private void describeMemberAdditions(@NonNull DecryptedGroupChange change, @NonNull List<UpdateDescription> updates) {
boolean editorIsYou = selfIds.matches(change.getEditorServiceIdBytes());
boolean editorIsYou = selfIds.matches(change.editorServiceIdBytes);
for (DecryptedMember member : change.getNewMembersList()) {
boolean newMemberIsYou = selfIds.matches(member.getAciBytes());
for (DecryptedMember member : change.newMembers) {
boolean newMemberIsYou = selfIds.matches(member.aciBytes);
if (editorIsYou) {
if (newMemberIsYou) {
updates.add(0, updateDescription(context.getString(R.string.MessageRecord_you_joined_the_group_via_the_group_link), R.drawable.ic_update_group_accept_16));
} else {
updates.add(updateDescription(R.string.MessageRecord_you_added_s, member.getAciBytes(), R.drawable.ic_update_group_add_16));
updates.add(updateDescription(R.string.MessageRecord_you_added_s, member.aciBytes, R.drawable.ic_update_group_add_16));
}
} else {
if (newMemberIsYou) {
updates.add(0, updateDescription(R.string.MessageRecord_s_added_you, change.getEditorServiceIdBytes(), R.drawable.ic_update_group_add_16));
updates.add(0, updateDescription(R.string.MessageRecord_s_added_you, change.editorServiceIdBytes, R.drawable.ic_update_group_add_16));
} else {
if (member.getAciBytes().equals(change.getEditorServiceIdBytes())) {
updates.add(updateDescription(R.string.MessageRecord_s_joined_the_group_via_the_group_link, member.getAciBytes(), R.drawable.ic_update_group_accept_16));
if (member.aciBytes.equals(change.editorServiceIdBytes)) {
updates.add(updateDescription(R.string.MessageRecord_s_joined_the_group_via_the_group_link, member.aciBytes, R.drawable.ic_update_group_accept_16));
} else {
updates.add(updateDescription(R.string.MessageRecord_s_added_s, change.getEditorServiceIdBytes(), member.getAciBytes(), R.drawable.ic_update_group_add_16));
updates.add(updateDescription(R.string.MessageRecord_s_added_s, change.editorServiceIdBytes, member.aciBytes, R.drawable.ic_update_group_add_16));
}
}
}
@@ -212,21 +218,21 @@ final class GroupsV2UpdateMessageProducer {
}
private void describeUnknownEditorMemberAdditions(@NonNull DecryptedGroupChange change, @NonNull List<UpdateDescription> updates) {
for (DecryptedMember member : change.getNewMembersList()) {
boolean newMemberIsYou = selfIds.matches(member.getAciBytes());
for (DecryptedMember member : change.newMembers) {
boolean newMemberIsYou = selfIds.matches(member.aciBytes);
if (newMemberIsYou) {
updates.add(0, updateDescription(context.getString(R.string.MessageRecord_you_joined_the_group), R.drawable.ic_update_group_add_16));
} else {
updates.add(updateDescription(R.string.MessageRecord_s_joined_the_group, member.getAciBytes(), R.drawable.ic_update_group_add_16));
updates.add(updateDescription(R.string.MessageRecord_s_joined_the_group, member.aciBytes, R.drawable.ic_update_group_add_16));
}
}
}
private void describeMemberRemovals(@NonNull DecryptedGroupChange change, @NonNull List<UpdateDescription> updates) {
boolean editorIsYou = selfIds.matches(change.getEditorServiceIdBytes());
boolean editorIsYou = selfIds.matches(change.editorServiceIdBytes);
for (ByteString member : change.getDeleteMembersList()) {
for (ByteString member : change.deleteMembers) {
boolean removedMemberIsYou = selfIds.matches(member);
if (editorIsYou) {
@@ -237,12 +243,12 @@ final class GroupsV2UpdateMessageProducer {
}
} else {
if (removedMemberIsYou) {
updates.add(updateDescription(R.string.MessageRecord_s_removed_you_from_the_group, change.getEditorServiceIdBytes(), R.drawable.ic_update_group_remove_16));
updates.add(updateDescription(R.string.MessageRecord_s_removed_you_from_the_group, change.editorServiceIdBytes, R.drawable.ic_update_group_remove_16));
} else {
if (member.equals(change.getEditorServiceIdBytes())) {
if (member.equals(change.editorServiceIdBytes)) {
updates.add(updateDescription(R.string.MessageRecord_s_left_the_group, member, R.drawable.ic_update_group_leave_16));
} else {
updates.add(updateDescription(R.string.MessageRecord_s_removed_s, change.getEditorServiceIdBytes(), member, R.drawable.ic_update_group_remove_16));
updates.add(updateDescription(R.string.MessageRecord_s_removed_s, change.editorServiceIdBytes, member, R.drawable.ic_update_group_remove_16));
}
}
}
@@ -250,7 +256,7 @@ final class GroupsV2UpdateMessageProducer {
}
private void describeUnknownEditorMemberRemovals(@NonNull DecryptedGroupChange change, @NonNull List<UpdateDescription> updates) {
for (ByteString member : change.getDeleteMembersList()) {
for (ByteString member : change.deleteMembers) {
boolean removedMemberIsYou = selfIds.matches(member);
if (removedMemberIsYou) {
@@ -262,29 +268,29 @@ final class GroupsV2UpdateMessageProducer {
}
private void describeModifyMemberRoles(@NonNull DecryptedGroupChange change, @NonNull List<UpdateDescription> updates) {
boolean editorIsYou = selfIds.matches(change.getEditorServiceIdBytes());
boolean editorIsYou = selfIds.matches(change.editorServiceIdBytes);
for (DecryptedModifyMemberRole roleChange : change.getModifyMemberRolesList()) {
boolean changedMemberIsYou = selfIds.matches(roleChange.getAciBytes());
if (roleChange.getRole() == Member.Role.ADMINISTRATOR) {
for (DecryptedModifyMemberRole roleChange : change.modifyMemberRoles) {
boolean changedMemberIsYou = selfIds.matches(roleChange.aciBytes);
if (roleChange.role == Member.Role.ADMINISTRATOR) {
if (editorIsYou) {
updates.add(updateDescription(R.string.MessageRecord_you_made_s_an_admin, roleChange.getAciBytes(), R.drawable.ic_update_group_role_16));
updates.add(updateDescription(R.string.MessageRecord_you_made_s_an_admin, roleChange.aciBytes, R.drawable.ic_update_group_role_16));
} else {
if (changedMemberIsYou) {
updates.add(updateDescription(R.string.MessageRecord_s_made_you_an_admin, change.getEditorServiceIdBytes(), R.drawable.ic_update_group_role_16));
updates.add(updateDescription(R.string.MessageRecord_s_made_you_an_admin, change.editorServiceIdBytes, R.drawable.ic_update_group_role_16));
} else {
updates.add(updateDescription(R.string.MessageRecord_s_made_s_an_admin, change.getEditorServiceIdBytes(), roleChange.getAciBytes(), R.drawable.ic_update_group_role_16));
updates.add(updateDescription(R.string.MessageRecord_s_made_s_an_admin, change.editorServiceIdBytes, roleChange.aciBytes, R.drawable.ic_update_group_role_16));
}
}
} else {
if (editorIsYou) {
updates.add(updateDescription(R.string.MessageRecord_you_revoked_admin_privileges_from_s, roleChange.getAciBytes(), R.drawable.ic_update_group_role_16));
updates.add(updateDescription(R.string.MessageRecord_you_revoked_admin_privileges_from_s, roleChange.aciBytes, R.drawable.ic_update_group_role_16));
} else {
if (changedMemberIsYou) {
updates.add(updateDescription(R.string.MessageRecord_s_revoked_your_admin_privileges, change.getEditorServiceIdBytes(), R.drawable.ic_update_group_role_16));
updates.add(updateDescription(R.string.MessageRecord_s_revoked_your_admin_privileges, change.editorServiceIdBytes, R.drawable.ic_update_group_role_16));
} else {
updates.add(updateDescription(R.string.MessageRecord_s_revoked_admin_privileges_from_s, change.getEditorServiceIdBytes(), roleChange.getAciBytes(), R.drawable.ic_update_group_role_16));
updates.add(updateDescription(R.string.MessageRecord_s_revoked_admin_privileges_from_s, change.editorServiceIdBytes, roleChange.aciBytes, R.drawable.ic_update_group_role_16));
}
}
}
@@ -292,37 +298,37 @@ final class GroupsV2UpdateMessageProducer {
}
private void describeUnknownEditorModifyMemberRoles(@NonNull DecryptedGroupChange change, @NonNull List<UpdateDescription> updates) {
for (DecryptedModifyMemberRole roleChange : change.getModifyMemberRolesList()) {
boolean changedMemberIsYou = selfIds.matches(roleChange.getAciBytes());
for (DecryptedModifyMemberRole roleChange : change.modifyMemberRoles) {
boolean changedMemberIsYou = selfIds.matches(roleChange.aciBytes);
if (roleChange.getRole() == Member.Role.ADMINISTRATOR) {
if (roleChange.role == Member.Role.ADMINISTRATOR) {
if (changedMemberIsYou) {
updates.add(updateDescription(context.getString(R.string.MessageRecord_you_are_now_an_admin), R.drawable.ic_update_group_role_16));
} else {
updates.add(updateDescription(R.string.MessageRecord_s_is_now_an_admin, roleChange.getAciBytes(), R.drawable.ic_update_group_role_16));
updates.add(updateDescription(R.string.MessageRecord_s_is_now_an_admin, roleChange.aciBytes, R.drawable.ic_update_group_role_16));
}
} else {
if (changedMemberIsYou) {
updates.add(updateDescription(context.getString(R.string.MessageRecord_you_are_no_longer_an_admin), R.drawable.ic_update_group_role_16));
} else {
updates.add(updateDescription(R.string.MessageRecord_s_is_no_longer_an_admin, roleChange.getAciBytes(), R.drawable.ic_update_group_role_16));
updates.add(updateDescription(R.string.MessageRecord_s_is_no_longer_an_admin, roleChange.aciBytes, R.drawable.ic_update_group_role_16));
}
}
}
}
private void describeInvitations(@NonNull DecryptedGroupChange change, @NonNull List<UpdateDescription> updates) {
boolean editorIsYou = selfIds.matches(change.getEditorServiceIdBytes());
boolean editorIsYou = selfIds.matches(change.editorServiceIdBytes);
int notYouInviteCount = 0;
for (DecryptedPendingMember invitee : change.getNewPendingMembersList()) {
boolean newMemberIsYou = selfIds.matches(invitee.getServiceIdBytes());
for (DecryptedPendingMember invitee : change.newPendingMembers) {
boolean newMemberIsYou = selfIds.matches(invitee.serviceIdBytes);
if (newMemberIsYou) {
updates.add(0, updateDescription(R.string.MessageRecord_s_invited_you_to_the_group, change.getEditorServiceIdBytes(), R.drawable.ic_update_group_add_16));
updates.add(0, updateDescription(R.string.MessageRecord_s_invited_you_to_the_group, change.editorServiceIdBytes, R.drawable.ic_update_group_add_16));
} else {
if (editorIsYou) {
updates.add(updateDescription(R.string.MessageRecord_you_invited_s_to_the_group, invitee.getServiceIdBytes(), R.drawable.ic_update_group_add_16));
updates.add(updateDescription(R.string.MessageRecord_you_invited_s_to_the_group, invitee.serviceIdBytes, R.drawable.ic_update_group_add_16));
} else {
notYouInviteCount++;
}
@@ -330,23 +336,23 @@ final class GroupsV2UpdateMessageProducer {
}
if (notYouInviteCount > 0) {
updates.add(updateDescription(R.plurals.MessageRecord_s_invited_members, notYouInviteCount, change.getEditorServiceIdBytes(), notYouInviteCount, R.drawable.ic_update_group_add_16));
updates.add(updateDescription(R.plurals.MessageRecord_s_invited_members, notYouInviteCount, change.editorServiceIdBytes, notYouInviteCount, R.drawable.ic_update_group_add_16));
}
}
private void describeUnknownEditorInvitations(@NonNull DecryptedGroupChange change, @NonNull List<UpdateDescription> updates) {
int notYouInviteCount = 0;
for (DecryptedPendingMember invitee : change.getNewPendingMembersList()) {
boolean newMemberIsYou = selfIds.matches(invitee.getServiceIdBytes());
for (DecryptedPendingMember invitee : change.newPendingMembers) {
boolean newMemberIsYou = selfIds.matches(invitee.serviceIdBytes);
if (newMemberIsYou) {
UUID uuid = UuidUtil.fromByteStringOrUnknown(invitee.getAddedByAci());
UUID uuid = UuidUtil.fromByteStringOrUnknown(invitee.addedByAci);
if (UuidUtil.UNKNOWN_UUID.equals(uuid)) {
updates.add(0, updateDescription(context.getString(R.string.MessageRecord_you_were_invited_to_the_group), R.drawable.ic_update_group_add_16));
} else {
updates.add(0, updateDescription(R.string.MessageRecord_s_invited_you_to_the_group, invitee.getAddedByAci(), R.drawable.ic_update_group_add_16));
updates.add(0, updateDescription(R.string.MessageRecord_s_invited_you_to_the_group, invitee.addedByAci, R.drawable.ic_update_group_add_16));
}
} else {
notYouInviteCount++;
@@ -359,19 +365,19 @@ final class GroupsV2UpdateMessageProducer {
}
private void describeRevokedInvitations(@NonNull DecryptedGroupChange change, @NonNull List<UpdateDescription> updates) {
boolean editorIsYou = selfIds.matches(change.getEditorServiceIdBytes());
boolean editorIsYou = selfIds.matches(change.editorServiceIdBytes);
int notDeclineCount = 0;
for (DecryptedPendingMemberRemoval invitee : change.getDeletePendingMembersList()) {
boolean decline = invitee.getServiceIdBytes().equals(change.getEditorServiceIdBytes());
for (DecryptedPendingMemberRemoval invitee : change.deletePendingMembers) {
boolean decline = invitee.serviceIdBytes.equals(change.editorServiceIdBytes);
if (decline) {
if (editorIsYou) {
updates.add(updateDescription(context.getString(R.string.MessageRecord_you_declined_the_invitation_to_the_group), R.drawable.ic_update_group_decline_16));
} else {
updates.add(updateDescription(context.getString(R.string.MessageRecord_someone_declined_an_invitation_to_the_group), R.drawable.ic_update_group_decline_16));
}
} else if (selfIds.matches(invitee.getServiceIdBytes())) {
updates.add(updateDescription(R.string.MessageRecord_s_revoked_your_invitation_to_the_group, change.getEditorServiceIdBytes(), R.drawable.ic_update_group_decline_16));
} else if (selfIds.matches(invitee.serviceIdBytes)) {
updates.add(updateDescription(R.string.MessageRecord_s_revoked_your_invitation_to_the_group, change.editorServiceIdBytes, R.drawable.ic_update_group_decline_16));
} else {
notDeclineCount++;
}
@@ -381,7 +387,7 @@ final class GroupsV2UpdateMessageProducer {
if (editorIsYou) {
updates.add(updateDescription(context.getResources().getQuantityString(R.plurals.MessageRecord_you_revoked_invites, notDeclineCount, notDeclineCount), R.drawable.ic_update_group_decline_16));
} else {
updates.add(updateDescription(R.plurals.MessageRecord_s_revoked_invites, notDeclineCount, change.getEditorServiceIdBytes(), notDeclineCount, R.drawable.ic_update_group_decline_16));
updates.add(updateDescription(R.plurals.MessageRecord_s_revoked_invites, notDeclineCount, change.editorServiceIdBytes, notDeclineCount, R.drawable.ic_update_group_decline_16));
}
}
}
@@ -389,8 +395,8 @@ final class GroupsV2UpdateMessageProducer {
private void describeUnknownEditorRevokedInvitations(@NonNull DecryptedGroupChange change, @NonNull List<UpdateDescription> updates) {
int notDeclineCount = 0;
for (DecryptedPendingMemberRemoval invitee : change.getDeletePendingMembersList()) {
boolean inviteeWasYou = selfIds.matches(invitee.getServiceIdBytes());
for (DecryptedPendingMemberRemoval invitee : change.deletePendingMembers) {
boolean inviteeWasYou = selfIds.matches(invitee.serviceIdBytes);
if (inviteeWasYou) {
updates.add(updateDescription(context.getString(R.string.MessageRecord_an_admin_revoked_your_invitation_to_the_group), R.drawable.ic_update_group_decline_16));
@@ -405,10 +411,10 @@ final class GroupsV2UpdateMessageProducer {
}
private void describePromotePending(@NonNull DecryptedGroupChange change, @NonNull List<UpdateDescription> updates) {
boolean editorIsYou = selfIds.matches(change.getEditorServiceIdBytes());
boolean editorIsYou = selfIds.matches(change.editorServiceIdBytes);
for (DecryptedMember newMember : change.getPromotePendingMembersList()) {
ByteString aci = newMember.getAciBytes();
for (DecryptedMember newMember : change.promotePendingMembers) {
ByteString aci = newMember.aciBytes;
boolean newMemberIsYou = selfIds.matches(aci);
if (editorIsYou) {
@@ -419,12 +425,12 @@ final class GroupsV2UpdateMessageProducer {
}
} else {
if (newMemberIsYou) {
updates.add(updateDescription(R.string.MessageRecord_s_added_you, change.getEditorServiceIdBytes(), R.drawable.ic_update_group_add_16));
updates.add(updateDescription(R.string.MessageRecord_s_added_you, change.editorServiceIdBytes, R.drawable.ic_update_group_add_16));
} else {
if (aci.equals(change.getEditorServiceIdBytes())) {
if (aci.equals(change.editorServiceIdBytes)) {
updates.add(updateDescription(R.string.MessageRecord_s_accepted_invite, aci, R.drawable.ic_update_group_accept_16));
} else {
updates.add(updateDescription(R.string.MessageRecord_s_added_invited_member_s, change.getEditorServiceIdBytes(), aci, R.drawable.ic_update_group_add_16));
updates.add(updateDescription(R.string.MessageRecord_s_added_invited_member_s, change.editorServiceIdBytes, aci, R.drawable.ic_update_group_add_16));
}
}
}
@@ -432,8 +438,8 @@ final class GroupsV2UpdateMessageProducer {
}
private void describeUnknownEditorPromotePending(@NonNull DecryptedGroupChange change, @NonNull List<UpdateDescription> updates) {
for (DecryptedMember newMember : change.getPromotePendingMembersList()) {
ByteString aci = newMember.getAciBytes();
for (DecryptedMember newMember : change.promotePendingMembers) {
ByteString aci = newMember.aciBytes;
boolean newMemberIsYou = selfIds.matches(aci);
if (newMemberIsYou) {
@@ -445,116 +451,116 @@ final class GroupsV2UpdateMessageProducer {
}
private void describeNewTitle(@NonNull DecryptedGroupChange change, @NonNull List<UpdateDescription> updates) {
boolean editorIsYou = selfIds.matches(change.getEditorServiceIdBytes());
boolean editorIsYou = selfIds.matches(change.editorServiceIdBytes);
if (change.hasNewTitle()) {
String newTitle = StringUtil.isolateBidi(change.getNewTitle().getValue());
if (change.newTitle != null) {
String newTitle = StringUtil.isolateBidi(change.newTitle.value_);
if (editorIsYou) {
updates.add(updateDescription(context.getString(R.string.MessageRecord_you_changed_the_group_name_to_s, newTitle), R.drawable.ic_update_group_name_16));
} else {
updates.add(updateDescription(R.string.MessageRecord_s_changed_the_group_name_to_s, change.getEditorServiceIdBytes(), newTitle, R.drawable.ic_update_group_name_16));
updates.add(updateDescription(R.string.MessageRecord_s_changed_the_group_name_to_s, change.editorServiceIdBytes, newTitle, R.drawable.ic_update_group_name_16));
}
}
}
private void describeNewDescription(@NonNull DecryptedGroupChange change, @NonNull List<UpdateDescription> updates) {
boolean editorIsYou = selfIds.matches(change.getEditorServiceIdBytes());
boolean editorIsYou = selfIds.matches(change.editorServiceIdBytes);
if (change.hasNewDescription()) {
if (change.newDescription != null) {
if (editorIsYou) {
updates.add(updateDescription(context.getString(R.string.MessageRecord_you_changed_the_group_description), R.drawable.ic_update_group_name_16));
} else {
updates.add(updateDescription(R.string.MessageRecord_s_changed_the_group_description, change.getEditorServiceIdBytes(), R.drawable.ic_update_group_name_16));
updates.add(updateDescription(R.string.MessageRecord_s_changed_the_group_description, change.editorServiceIdBytes, R.drawable.ic_update_group_name_16));
}
}
}
private void describeUnknownEditorNewTitle(@NonNull DecryptedGroupChange change, @NonNull List<UpdateDescription> updates) {
if (change.hasNewTitle()) {
updates.add(updateDescription(context.getString(R.string.MessageRecord_the_group_name_has_changed_to_s, StringUtil.isolateBidi(change.getNewTitle().getValue())), R.drawable.ic_update_group_name_16));
if (change.newTitle != null) {
updates.add(updateDescription(context.getString(R.string.MessageRecord_the_group_name_has_changed_to_s, StringUtil.isolateBidi(change.newTitle.value_)), R.drawable.ic_update_group_name_16));
}
}
private void describeUnknownEditorNewDescription(@NonNull DecryptedGroupChange change, @NonNull List<UpdateDescription> updates) {
if (change.hasNewDescription()) {
if (change.newDescription != null) {
updates.add(updateDescription(context.getString(R.string.MessageRecord_the_group_description_has_changed), R.drawable.ic_update_group_name_16));
}
}
private void describeNewAvatar(@NonNull DecryptedGroupChange change, @NonNull List<UpdateDescription> updates) {
boolean editorIsYou = selfIds.matches(change.getEditorServiceIdBytes());
boolean editorIsYou = selfIds.matches(change.editorServiceIdBytes);
if (change.hasNewAvatar()) {
if (change.newAvatar != null) {
if (editorIsYou) {
updates.add(updateDescription(context.getString(R.string.MessageRecord_you_changed_the_group_avatar), R.drawable.ic_update_group_avatar_16));
} else {
updates.add(updateDescription(R.string.MessageRecord_s_changed_the_group_avatar, change.getEditorServiceIdBytes(), R.drawable.ic_update_group_avatar_16));
updates.add(updateDescription(R.string.MessageRecord_s_changed_the_group_avatar, change.editorServiceIdBytes, R.drawable.ic_update_group_avatar_16));
}
}
}
private void describeUnknownEditorNewAvatar(@NonNull DecryptedGroupChange change, @NonNull List<UpdateDescription> updates) {
if (change.hasNewAvatar()) {
if (change.newAvatar != null) {
updates.add(updateDescription(context.getString(R.string.MessageRecord_the_group_group_avatar_has_been_changed), R.drawable.ic_update_group_avatar_16));
}
}
void describeNewTimer(@NonNull DecryptedGroupChange change, @NonNull List<UpdateDescription> updates) {
boolean editorIsYou = selfIds.matches(change.getEditorServiceIdBytes());
boolean editorIsYou = selfIds.matches(change.editorServiceIdBytes);
if (change.hasNewTimer()) {
String time = ExpirationUtil.getExpirationDisplayValue(context, change.getNewTimer().getDuration());
if (change.newTimer != null) {
String time = ExpirationUtil.getExpirationDisplayValue(context, change.newTimer.duration);
if (editorIsYou) {
updates.add(updateDescription(context.getString(R.string.MessageRecord_you_set_disappearing_message_time_to_s, time), R.drawable.ic_update_timer_16));
} else {
updates.add(updateDescription(R.string.MessageRecord_s_set_disappearing_message_time_to_s, change.getEditorServiceIdBytes(), time, R.drawable.ic_update_timer_16));
updates.add(updateDescription(R.string.MessageRecord_s_set_disappearing_message_time_to_s, change.editorServiceIdBytes, time, R.drawable.ic_update_timer_16));
}
}
}
private void describeUnknownEditorNewTimer(@NonNull DecryptedGroupChange change, @NonNull List<UpdateDescription> updates) {
if (change.hasNewTimer()) {
String time = ExpirationUtil.getExpirationDisplayValue(context, change.getNewTimer().getDuration());
if (change.newTimer != null) {
String time = ExpirationUtil.getExpirationDisplayValue(context, change.newTimer.duration);
updates.add(updateDescription(context.getString(R.string.MessageRecord_disappearing_message_time_set_to_s, time), R.drawable.ic_update_timer_16));
}
}
private void describeNewAttributeAccess(@NonNull DecryptedGroupChange change, @NonNull List<UpdateDescription> updates) {
boolean editorIsYou = selfIds.matches(change.getEditorServiceIdBytes());
boolean editorIsYou = selfIds.matches(change.editorServiceIdBytes);
if (change.getNewAttributeAccess() != AccessControl.AccessRequired.UNKNOWN) {
String accessLevel = GV2AccessLevelUtil.toString(context, change.getNewAttributeAccess());
if (change.newAttributeAccess != AccessControl.AccessRequired.UNKNOWN) {
String accessLevel = GV2AccessLevelUtil.toString(context, change.newAttributeAccess);
if (editorIsYou) {
updates.add(updateDescription(context.getString(R.string.MessageRecord_you_changed_who_can_edit_group_info_to_s, accessLevel), R.drawable.ic_update_group_role_16));
} else {
updates.add(updateDescription(R.string.MessageRecord_s_changed_who_can_edit_group_info_to_s, change.getEditorServiceIdBytes(), accessLevel, R.drawable.ic_update_group_role_16));
updates.add(updateDescription(R.string.MessageRecord_s_changed_who_can_edit_group_info_to_s, change.editorServiceIdBytes, accessLevel, R.drawable.ic_update_group_role_16));
}
}
}
private void describeUnknownEditorNewAttributeAccess(@NonNull DecryptedGroupChange change, @NonNull List<UpdateDescription> updates) {
if (change.getNewAttributeAccess() != AccessControl.AccessRequired.UNKNOWN) {
String accessLevel = GV2AccessLevelUtil.toString(context, change.getNewAttributeAccess());
if (change.newAttributeAccess != AccessControl.AccessRequired.UNKNOWN) {
String accessLevel = GV2AccessLevelUtil.toString(context, change.newAttributeAccess);
updates.add(updateDescription(context.getString(R.string.MessageRecord_who_can_edit_group_info_has_been_changed_to_s, accessLevel), R.drawable.ic_update_group_role_16));
}
}
private void describeNewMembershipAccess(@NonNull DecryptedGroupChange change, @NonNull List<UpdateDescription> updates) {
boolean editorIsYou = selfIds.matches(change.getEditorServiceIdBytes());
boolean editorIsYou = selfIds.matches(change.editorServiceIdBytes);
if (change.getNewMemberAccess() != AccessControl.AccessRequired.UNKNOWN) {
String accessLevel = GV2AccessLevelUtil.toString(context, change.getNewMemberAccess());
if (change.newMemberAccess != AccessControl.AccessRequired.UNKNOWN) {
String accessLevel = GV2AccessLevelUtil.toString(context, change.newMemberAccess);
if (editorIsYou) {
updates.add(updateDescription(context.getString(R.string.MessageRecord_you_changed_who_can_edit_group_membership_to_s, accessLevel), R.drawable.ic_update_group_role_16));
} else {
updates.add(updateDescription(R.string.MessageRecord_s_changed_who_can_edit_group_membership_to_s, change.getEditorServiceIdBytes(), accessLevel, R.drawable.ic_update_group_role_16));
updates.add(updateDescription(R.string.MessageRecord_s_changed_who_can_edit_group_membership_to_s, change.editorServiceIdBytes, accessLevel, R.drawable.ic_update_group_role_16));
}
}
}
private void describeUnknownEditorNewMembershipAccess(@NonNull DecryptedGroupChange change, @NonNull List<UpdateDescription> updates) {
if (change.getNewMemberAccess() != AccessControl.AccessRequired.UNKNOWN) {
String accessLevel = GV2AccessLevelUtil.toString(context, change.getNewMemberAccess());
if (change.newMemberAccess != AccessControl.AccessRequired.UNKNOWN) {
String accessLevel = GV2AccessLevelUtil.toString(context, change.newMemberAccess);
updates.add(updateDescription(context.getString(R.string.MessageRecord_who_can_edit_group_membership_has_been_changed_to_s, accessLevel), R.drawable.ic_update_group_role_16));
}
}
@@ -565,14 +571,15 @@ final class GroupsV2UpdateMessageProducer {
{
AccessControl.AccessRequired previousAccessControl = null;
if (previousGroupState != null) {
previousAccessControl = previousGroupState.getAccessControl().getAddFromInviteLink();
if (previousGroupState != null && previousGroupState.accessControl != null) {
previousAccessControl = previousGroupState.accessControl.addFromInviteLink;
}
boolean editorIsYou = selfIds.matches(change.getEditorServiceIdBytes());
boolean editorIsYou = selfIds.matches(change.editorServiceIdBytes);
boolean groupLinkEnabled = false;
switch (change.getNewInviteLinkAccess()) {
//noinspection EnhancedSwitchMigration
switch (change.newInviteLinkAccess) {
case ANY:
groupLinkEnabled = true;
if (editorIsYou) {
@@ -583,9 +590,9 @@ final class GroupsV2UpdateMessageProducer {
}
} else {
if (previousAccessControl == AccessControl.AccessRequired.ADMINISTRATOR) {
updates.add(updateDescription(R.string.MessageRecord_s_turned_off_admin_approval_for_the_group_link, change.getEditorServiceIdBytes(), R.drawable.ic_update_group_role_16));
updates.add(updateDescription(R.string.MessageRecord_s_turned_off_admin_approval_for_the_group_link, change.editorServiceIdBytes, R.drawable.ic_update_group_role_16));
} else {
updates.add(updateDescription(R.string.MessageRecord_s_turned_on_the_group_link_with_admin_approval_off, change.getEditorServiceIdBytes(), R.drawable.ic_update_group_role_16));
updates.add(updateDescription(R.string.MessageRecord_s_turned_on_the_group_link_with_admin_approval_off, change.editorServiceIdBytes, R.drawable.ic_update_group_role_16));
}
}
break;
@@ -599,9 +606,9 @@ final class GroupsV2UpdateMessageProducer {
}
} else {
if (previousAccessControl == AccessControl.AccessRequired.ANY) {
updates.add(updateDescription(R.string.MessageRecord_s_turned_on_admin_approval_for_the_group_link, change.getEditorServiceIdBytes(), R.drawable.ic_update_group_role_16));
updates.add(updateDescription(R.string.MessageRecord_s_turned_on_admin_approval_for_the_group_link, change.editorServiceIdBytes, R.drawable.ic_update_group_role_16));
} else {
updates.add(updateDescription(R.string.MessageRecord_s_turned_on_the_group_link_with_admin_approval_on, change.getEditorServiceIdBytes(), R.drawable.ic_update_group_role_16));
updates.add(updateDescription(R.string.MessageRecord_s_turned_on_the_group_link_with_admin_approval_on, change.editorServiceIdBytes, R.drawable.ic_update_group_role_16));
}
}
break;
@@ -609,16 +616,16 @@ final class GroupsV2UpdateMessageProducer {
if (editorIsYou) {
updates.add(updateDescription(context.getString(R.string.MessageRecord_you_turned_off_the_group_link), R.drawable.ic_update_group_role_16));
} else {
updates.add(updateDescription(R.string.MessageRecord_s_turned_off_the_group_link, change.getEditorServiceIdBytes(), R.drawable.ic_update_group_role_16));
updates.add(updateDescription(R.string.MessageRecord_s_turned_off_the_group_link, change.editorServiceIdBytes, R.drawable.ic_update_group_role_16));
}
break;
}
if (!groupLinkEnabled && change.getNewInviteLinkPassword().size() > 0) {
if (!groupLinkEnabled && change.newInviteLinkPassword.size() > 0) {
if (editorIsYou) {
updates.add(updateDescription(context.getString(R.string.MessageRecord_you_reset_the_group_link), R.drawable.ic_update_group_role_16));
} else {
updates.add(updateDescription(R.string.MessageRecord_s_reset_the_group_link, change.getEditorServiceIdBytes(), R.drawable.ic_update_group_role_16));
updates.add(updateDescription(R.string.MessageRecord_s_reset_the_group_link, change.editorServiceIdBytes, R.drawable.ic_update_group_role_16));
}
}
}
@@ -629,11 +636,12 @@ final class GroupsV2UpdateMessageProducer {
{
AccessControl.AccessRequired previousAccessControl = null;
if (previousGroupState != null) {
previousAccessControl = previousGroupState.getAccessControl().getAddFromInviteLink();
if (previousGroupState != null && previousGroupState.accessControl != null) {
previousAccessControl = previousGroupState.accessControl.addFromInviteLink;
}
switch (change.getNewInviteLinkAccess()) {
//noinspection EnhancedSwitchMigration
switch (change.newInviteLinkAccess) {
case ANY:
if (previousAccessControl == AccessControl.AccessRequired.ADMINISTRATOR) {
updates.add(updateDescription(context.getString(R.string.MessageRecord_the_admin_approval_for_the_group_link_has_been_turned_off), R.drawable.ic_update_group_role_16));
@@ -653,69 +661,69 @@ final class GroupsV2UpdateMessageProducer {
break;
}
if (change.getNewInviteLinkPassword().size() > 0) {
if (change.newInviteLinkPassword.size() > 0) {
updates.add(updateDescription(context.getString(R.string.MessageRecord_the_group_link_has_been_reset), R.drawable.ic_update_group_role_16));
}
}
private void describeRequestingMembers(@NonNull DecryptedGroupChange change, @NonNull List<UpdateDescription> updates) {
Set<ByteString> deleteRequestingUuids = new HashSet<>(change.getDeleteRequestingMembersList());
Set<ByteString> deleteRequestingUuids = new HashSet<>(change.deleteRequestingMembers);
for (DecryptedRequestingMember member : change.getNewRequestingMembersList()) {
boolean requestingMemberIsYou = selfIds.matches(member.getAciBytes());
for (DecryptedRequestingMember member : change.newRequestingMembers) {
boolean requestingMemberIsYou = selfIds.matches(member.aciBytes);
if (requestingMemberIsYou) {
updates.add(updateDescription(context.getString(R.string.MessageRecord_you_sent_a_request_to_join_the_group), R.drawable.ic_update_group_16));
} else {
if (deleteRequestingUuids.contains(member.getAciBytes())) {
if (deleteRequestingUuids.contains(member.aciBytes)) {
updates.add(updateDescription(R.plurals.MessageRecord_s_requested_and_cancelled_their_request_to_join_via_the_group_link,
change.getDeleteRequestingMembersCount(),
member.getAciBytes(),
change.getDeleteRequestingMembersCount(),
change.deleteRequestingMembers.size(),
member.aciBytes,
change.deleteRequestingMembers.size(),
R.drawable.ic_update_group_16));
} else {
updates.add(updateDescription(R.string.MessageRecord_s_requested_to_join_via_the_group_link, member.getAciBytes(), R.drawable.ic_update_group_16));
updates.add(updateDescription(R.string.MessageRecord_s_requested_to_join_via_the_group_link, member.aciBytes, R.drawable.ic_update_group_16));
}
}
}
}
private void describeRequestingMembersApprovals(@NonNull DecryptedGroupChange change, @NonNull List<UpdateDescription> updates) {
for (DecryptedApproveMember requestingMember : change.getPromoteRequestingMembersList()) {
boolean requestingMemberIsYou = selfIds.matches(requestingMember.getAciBytes());
for (DecryptedApproveMember requestingMember : change.promoteRequestingMembers) {
boolean requestingMemberIsYou = selfIds.matches(requestingMember.aciBytes);
if (requestingMemberIsYou) {
updates.add(updateDescription(R.string.MessageRecord_s_approved_your_request_to_join_the_group, change.getEditorServiceIdBytes(), R.drawable.ic_update_group_accept_16));
updates.add(updateDescription(R.string.MessageRecord_s_approved_your_request_to_join_the_group, change.editorServiceIdBytes, R.drawable.ic_update_group_accept_16));
} else {
boolean editorIsYou = selfIds.matches(change.getEditorServiceIdBytes());
boolean editorIsYou = selfIds.matches(change.editorServiceIdBytes);
if (editorIsYou) {
updates.add(updateDescription(R.string.MessageRecord_you_approved_a_request_to_join_the_group_from_s, requestingMember.getAciBytes(), R.drawable.ic_update_group_accept_16));
updates.add(updateDescription(R.string.MessageRecord_you_approved_a_request_to_join_the_group_from_s, requestingMember.aciBytes, R.drawable.ic_update_group_accept_16));
} else {
updates.add(updateDescription(R.string.MessageRecord_s_approved_a_request_to_join_the_group_from_s, change.getEditorServiceIdBytes(), requestingMember.getAciBytes(), R.drawable.ic_update_group_accept_16));
updates.add(updateDescription(R.string.MessageRecord_s_approved_a_request_to_join_the_group_from_s, change.editorServiceIdBytes, requestingMember.aciBytes, R.drawable.ic_update_group_accept_16));
}
}
}
}
private void describeUnknownEditorRequestingMembersApprovals(@NonNull DecryptedGroupChange change, @NonNull List<UpdateDescription> updates) {
for (DecryptedApproveMember requestingMember : change.getPromoteRequestingMembersList()) {
boolean requestingMemberIsYou = selfIds.matches(requestingMember.getAciBytes());
for (DecryptedApproveMember requestingMember : change.promoteRequestingMembers) {
boolean requestingMemberIsYou = selfIds.matches(requestingMember.aciBytes);
if (requestingMemberIsYou) {
updates.add(updateDescription(context.getString(R.string.MessageRecord_your_request_to_join_the_group_has_been_approved), R.drawable.ic_update_group_accept_16));
} else {
updates.add(updateDescription(R.string.MessageRecord_a_request_to_join_the_group_from_s_has_been_approved, requestingMember.getAciBytes(), R.drawable.ic_update_group_accept_16));
updates.add(updateDescription(R.string.MessageRecord_a_request_to_join_the_group_from_s_has_been_approved, requestingMember.aciBytes, R.drawable.ic_update_group_accept_16));
}
}
}
private void describeRequestingMembersDeletes(@NonNull DecryptedGroupChange change, @NonNull List<UpdateDescription> updates) {
Set<ByteString> newRequestingUuids = change.getNewRequestingMembersList().stream().map(DecryptedRequestingMember::getAciBytes).collect(Collectors.toSet());
Set<ByteString> newRequestingUuids = change.newRequestingMembers.stream().map(m -> m.aciBytes).collect(Collectors.toSet());
boolean editorIsYou = selfIds.matches(change.getEditorServiceIdBytes());
boolean editorIsYou = selfIds.matches(change.editorServiceIdBytes);
for (ByteString requestingMember : change.getDeleteRequestingMembersList()) {
for (ByteString requestingMember : change.deleteRequestingMembers) {
if (newRequestingUuids.contains(requestingMember)) {
continue;
}
@@ -729,19 +737,19 @@ final class GroupsV2UpdateMessageProducer {
updates.add(updateDescription(context.getString(R.string.MessageRecord_your_request_to_join_the_group_has_been_denied_by_an_admin), R.drawable.ic_update_group_decline_16));
}
} else {
boolean editorIsCanceledMember = change.getEditorServiceIdBytes().equals(requestingMember);
boolean editorIsCanceledMember = change.editorServiceIdBytes.equals(requestingMember);
if (editorIsCanceledMember) {
updates.add(updateDescription(R.string.MessageRecord_s_canceled_their_request_to_join_the_group, requestingMember, R.drawable.ic_update_group_decline_16));
} else {
updates.add(updateDescription(R.string.MessageRecord_s_denied_a_request_to_join_the_group_from_s, change.getEditorServiceIdBytes(), requestingMember, R.drawable.ic_update_group_decline_16));
updates.add(updateDescription(R.string.MessageRecord_s_denied_a_request_to_join_the_group_from_s, change.editorServiceIdBytes, requestingMember, R.drawable.ic_update_group_decline_16));
}
}
}
}
private void describeUnknownEditorRequestingMembersDeletes(@NonNull DecryptedGroupChange change, @NonNull List<UpdateDescription> updates) {
for (ByteString requestingMember : change.getDeleteRequestingMembersList()) {
for (ByteString requestingMember : change.deleteRequestingMembers) {
boolean requestingMemberIsYou = selfIds.matches(requestingMember);
if (requestingMemberIsYou) {
@@ -753,36 +761,36 @@ final class GroupsV2UpdateMessageProducer {
}
private void describeAnnouncementGroupChange(@NonNull DecryptedGroupChange change, @NonNull List<UpdateDescription> updates) {
boolean editorIsYou = selfIds.matches(change.getEditorServiceIdBytes());
boolean editorIsYou = selfIds.matches(change.editorServiceIdBytes);
if (change.getNewIsAnnouncementGroup() == EnabledState.ENABLED) {
if (change.newIsAnnouncementGroup == EnabledState.ENABLED) {
if (editorIsYou) {
updates.add(updateDescription(context.getString(R.string.MessageRecord_you_allow_only_admins_to_send), R.drawable.ic_update_group_role_16));
} else {
updates.add(updateDescription(R.string.MessageRecord_s_allow_only_admins_to_send, change.getEditorServiceIdBytes(), R.drawable.ic_update_group_role_16));
updates.add(updateDescription(R.string.MessageRecord_s_allow_only_admins_to_send, change.editorServiceIdBytes, R.drawable.ic_update_group_role_16));
}
} else if (change.getNewIsAnnouncementGroup() == EnabledState.DISABLED) {
} else if (change.newIsAnnouncementGroup == EnabledState.DISABLED) {
if (editorIsYou) {
updates.add(updateDescription(context.getString(R.string.MessageRecord_you_allow_all_members_to_send), R.drawable.ic_update_group_role_16));
} else {
updates.add(updateDescription(R.string.MessageRecord_s_allow_all_members_to_send, change.getEditorServiceIdBytes(), R.drawable.ic_update_group_role_16));
updates.add(updateDescription(R.string.MessageRecord_s_allow_all_members_to_send, change.editorServiceIdBytes, R.drawable.ic_update_group_role_16));
}
}
}
private void describeUnknownEditorAnnouncementGroupChange(@NonNull DecryptedGroupChange change, @NonNull List<UpdateDescription> updates) {
if (change.getNewIsAnnouncementGroup() == EnabledState.ENABLED) {
if (change.newIsAnnouncementGroup == EnabledState.ENABLED) {
updates.add(updateDescription(context.getString(R.string.MessageRecord_allow_only_admins_to_send), R.drawable.ic_update_group_role_16));
} else if (change.getNewIsAnnouncementGroup() == EnabledState.DISABLED) {
} else if (change.newIsAnnouncementGroup == EnabledState.DISABLED) {
updates.add(updateDescription(context.getString(R.string.MessageRecord_allow_all_members_to_send), R.drawable.ic_update_group_role_16));
}
}
private void describePromotePendingPniAci(@NonNull DecryptedGroupChange change, @NonNull List<UpdateDescription> updates) {
boolean editorIsYou = selfIds.matches(change.getEditorServiceIdBytes());
boolean editorIsYou = selfIds.matches(change.editorServiceIdBytes);
for (DecryptedMember newMember : change.getPromotePendingPniAciMembersList()) {
ByteString uuid = newMember.getAciBytes();
for (DecryptedMember newMember : change.promotePendingPniAciMembers) {
ByteString uuid = newMember.aciBytes;
boolean newMemberIsYou = selfIds.matches(uuid);
if (editorIsYou) {
@@ -793,12 +801,12 @@ final class GroupsV2UpdateMessageProducer {
}
} else {
if (newMemberIsYou) {
updates.add(updateDescription(R.string.MessageRecord_s_added_you, change.getEditorServiceIdBytes(), R.drawable.ic_update_group_add_16));
updates.add(updateDescription(R.string.MessageRecord_s_added_you, change.editorServiceIdBytes, R.drawable.ic_update_group_add_16));
} else {
if (uuid.equals(change.getEditorServiceIdBytes())) {
if (uuid.equals(change.editorServiceIdBytes)) {
updates.add(updateDescription(R.string.MessageRecord_s_accepted_invite, uuid, R.drawable.ic_update_group_accept_16));
} else {
updates.add(updateDescription(R.string.MessageRecord_s_added_invited_member_s, change.getEditorServiceIdBytes(), uuid, R.drawable.ic_update_group_add_16));
updates.add(updateDescription(R.string.MessageRecord_s_added_invited_member_s, change.editorServiceIdBytes, uuid, R.drawable.ic_update_group_add_16));
}
}
}
@@ -806,8 +814,8 @@ final class GroupsV2UpdateMessageProducer {
}
private void describeUnknownEditorPromotePendingPniAci(@NonNull DecryptedGroupChange change, @NonNull List<UpdateDescription> updates) {
for (DecryptedMember newMember : change.getPromotePendingPniAciMembersList()) {
ByteString aci = newMember.getAciBytes();
for (DecryptedMember newMember : change.promotePendingPniAciMembers) {
ByteString aci = newMember.aciBytes;
boolean newMemberIsYou = selfIds.matches(aci);
if (newMemberIsYou) {

View File

@@ -2,7 +2,7 @@ package org.thoughtcrime.securesms.database.model
import org.thoughtcrime.securesms.recipients.RecipientId
import org.whispersystems.signalservice.api.crypto.ContentHint
import org.whispersystems.signalservice.internal.push.SignalServiceProtos
import org.whispersystems.signalservice.internal.push.Content
/**
* Model class for reading from the [org.thoughtcrime.securesms.database.MessageSendLogTables].
@@ -10,7 +10,7 @@ import org.whispersystems.signalservice.internal.push.SignalServiceProtos
data class MessageLogEntry(
val recipientId: RecipientId,
val dateSent: Long,
val content: SignalServiceProtos.Content,
val content: Content,
val contentHint: ContentHint,
@get:JvmName("isUrgent")
val urgent: Boolean,

View File

@@ -31,8 +31,6 @@ import androidx.annotation.WorkerThread;
import androidx.core.content.ContextCompat;
import com.annimon.stream.Stream;
import com.google.protobuf.ByteString;
import com.google.protobuf.InvalidProtocolBufferException;
import org.signal.core.util.StringUtil;
import org.signal.core.util.logging.Log;
@@ -64,8 +62,8 @@ import org.thoughtcrime.securesms.util.ExpirationUtil;
import org.thoughtcrime.securesms.util.GroupUtil;
import org.thoughtcrime.securesms.util.Util;
import org.whispersystems.signalservice.api.groupsv2.DecryptedGroupUtil;
import org.whispersystems.signalservice.api.push.ServiceId.ACI;
import org.whispersystems.signalservice.api.push.ServiceId;
import org.whispersystems.signalservice.api.push.ServiceId.ACI;
import org.whispersystems.signalservice.api.util.UuidUtil;
import java.io.IOException;
@@ -77,6 +75,8 @@ import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Function;
import okio.ByteString;
/**
* The base class for message record models that are displayed in
* conversations, as opposed to models that are displayed in a thread list.
@@ -235,26 +235,26 @@ public abstract class MessageRecord extends DisplayRecord {
return fromRecipient(getFromRecipient(), r -> context.getString(R.string.MessageRecord_a_message_from_s_couldnt_be_delivered, r.getDisplayName(context)), R.drawable.ic_error_outline_14);
} else if (isThreadMergeEventType()) {
try {
ThreadMergeEvent event = ThreadMergeEvent.parseFrom(Base64.decodeOrThrow(getBody()));
ThreadMergeEvent event = ThreadMergeEvent.ADAPTER.decode(Base64.decodeOrThrow(getBody()));
if (event.getPreviousE164().isEmpty()) {
if (event.previousE164.isEmpty()) {
return fromRecipient(getFromRecipient(), r -> context.getString(R.string.MessageRecord_your_message_history_with_s_and_another_chat_has_been_merged, r.getDisplayName(context)), R.drawable.ic_thread_merge_16);
} else {
return fromRecipient(getFromRecipient(), r -> context.getString(R.string.MessageRecord_your_message_history_with_s_and_their_number_s_has_been_merged, r.getDisplayName(context), PhoneNumberFormatter.prettyPrint(event.getPreviousE164())), R.drawable.ic_thread_merge_16);
return fromRecipient(getFromRecipient(), r -> context.getString(R.string.MessageRecord_your_message_history_with_s_and_their_number_s_has_been_merged, r.getDisplayName(context), PhoneNumberFormatter.prettyPrint(event.previousE164)), R.drawable.ic_thread_merge_16);
}
} catch (InvalidProtocolBufferException e) {
} catch (IOException e) {
throw new AssertionError(e);
}
} else if (isSessionSwitchoverEventType()) {
try {
SessionSwitchoverEvent event = SessionSwitchoverEvent.parseFrom(Base64.decodeOrThrow(getBody()));
SessionSwitchoverEvent event = SessionSwitchoverEvent.ADAPTER.decode(Base64.decodeOrThrow(getBody()));
if (event.getE164().isEmpty()) {
if (event.e164.isEmpty()) {
return fromRecipient(getFromRecipient(), r -> context.getString(R.string.MessageRecord_your_safety_number_with_s_has_changed, r.getDisplayName(context)), R.drawable.ic_update_safety_number_16);
} else {
return fromRecipient(getFromRecipient(), r -> context.getString(R.string.MessageRecord_s_belongs_to_s, PhoneNumberFormatter.prettyPrint(r.requireE164()), r.getDisplayName(context)), R.drawable.ic_update_info_16);
}
} catch (InvalidProtocolBufferException e) {
} catch (IOException e) {
throw new AssertionError(e);
}
} else if (isSmsExportType()) {
@@ -282,7 +282,7 @@ public abstract class MessageRecord extends DisplayRecord {
if (decryptedGroupV2Context == null) {
return false;
}
DecryptedGroupChange change = decryptedGroupV2Context.getChange();
DecryptedGroupChange change = decryptedGroupV2Context.change;
return selfCreatedGroup(change);
}
@@ -296,7 +296,7 @@ public abstract class MessageRecord extends DisplayRecord {
DecryptedGroupV2Context decryptedGroupV2Context;
try {
byte[] decoded = Base64.decode(getBody());
decryptedGroupV2Context = DecryptedGroupV2Context.parseFrom(decoded);
decryptedGroupV2Context = DecryptedGroupV2Context.ADAPTER.decode(decoded);
} catch (IOException e) {
Log.w(TAG, "GV2 Message update detail could not be read", e);
@@ -305,28 +305,29 @@ public abstract class MessageRecord extends DisplayRecord {
return decryptedGroupV2Context;
}
private static boolean selfCreatedGroup(@NonNull DecryptedGroupChange change) {
return change.getRevision() == 0 &&
change.getEditorServiceIdBytes().equals(SignalStore.account().requireAci().toByteString());
private static boolean selfCreatedGroup(@Nullable DecryptedGroupChange change) {
return change != null &&
change.revision == 0 &&
change.editorServiceIdBytes.equals(SignalStore.account().requireAci().toByteString());
}
public static @NonNull UpdateDescription getGv2ChangeDescription(@NonNull Context context, @NonNull String body, @Nullable Consumer<RecipientId> recipientClickHandler) {
try {
byte[] decoded = Base64.decode(body);
DecryptedGroupV2Context decryptedGroupV2Context = DecryptedGroupV2Context.parseFrom(decoded);
DecryptedGroupV2Context decryptedGroupV2Context = DecryptedGroupV2Context.ADAPTER.decode(decoded);
GroupsV2UpdateMessageProducer updateMessageProducer = new GroupsV2UpdateMessageProducer(context, SignalStore.account().getServiceIds(), recipientClickHandler);
if (decryptedGroupV2Context.hasChange() && (decryptedGroupV2Context.getGroupState().getRevision() != 0 || decryptedGroupV2Context.hasPreviousGroupState())) {
return UpdateDescription.concatWithNewLines(updateMessageProducer.describeChanges(decryptedGroupV2Context.getPreviousGroupState(), decryptedGroupV2Context.getChange()));
if (decryptedGroupV2Context.change != null && ((decryptedGroupV2Context.groupState != null && decryptedGroupV2Context.groupState.revision != 0) || decryptedGroupV2Context.previousGroupState != null)) {
return UpdateDescription.concatWithNewLines(updateMessageProducer.describeChanges(decryptedGroupV2Context.previousGroupState, decryptedGroupV2Context.change));
} else {
List<UpdateDescription> newGroupDescriptions = new ArrayList<>();
newGroupDescriptions.add(updateMessageProducer.describeNewGroup(decryptedGroupV2Context.getGroupState(), decryptedGroupV2Context.getChange()));
newGroupDescriptions.add(updateMessageProducer.describeNewGroup(decryptedGroupV2Context.groupState, decryptedGroupV2Context.change));
if (decryptedGroupV2Context.getChange().hasNewTimer()) {
updateMessageProducer.describeNewTimer(decryptedGroupV2Context.getChange(), newGroupDescriptions);
if (decryptedGroupV2Context.change != null && decryptedGroupV2Context.change.newTimer != null) {
updateMessageProducer.describeNewTimer(decryptedGroupV2Context.change, newGroupDescriptions);
}
if (selfCreatedGroup(decryptedGroupV2Context.getChange())) {
if (selfCreatedGroup(decryptedGroupV2Context.change)) {
newGroupDescriptions.add(staticUpdateDescription(context.getString(R.string.MessageRecord_invite_friends_to_this_group), 0));
}
return UpdateDescription.concatWithNewLines(newGroupDescriptions);
@@ -344,11 +345,11 @@ public abstract class MessageRecord extends DisplayRecord {
return null;
}
DecryptedGroup groupState = decryptedGroupV2Context.getGroupState();
boolean invited = DecryptedGroupUtil.findPendingByServiceId(groupState.getPendingMembersList(), SignalStore.account().requireAci()).isPresent();
DecryptedGroup groupState = decryptedGroupV2Context.groupState;
boolean invited = groupState != null && DecryptedGroupUtil.findPendingByServiceId(groupState.pendingMembers, SignalStore.account().requireAci()).isPresent();
if (decryptedGroupV2Context.hasChange()) {
ServiceId changeEditor = ServiceId.parseOrNull(decryptedGroupV2Context.getChange().getEditorServiceIdBytes());
if (decryptedGroupV2Context.change != null) {
ServiceId changeEditor = ServiceId.parseOrNull(decryptedGroupV2Context.change.editorServiceIdBytes);
if (changeEditor != null) {
if (changeEditor instanceof ACI) {
@@ -394,12 +395,12 @@ public abstract class MessageRecord extends DisplayRecord {
private @NonNull String getProfileChangeDescription(@NonNull Context context) {
try {
byte[] decoded = Base64.decode(getBody());
ProfileChangeDetails profileChangeDetails = ProfileChangeDetails.parseFrom(decoded);
ProfileChangeDetails profileChangeDetails = ProfileChangeDetails.ADAPTER.decode(decoded);
if (profileChangeDetails.hasProfileNameChange()) {
if (profileChangeDetails.profileNameChange != null) {
String displayName = getFromRecipient().getDisplayName(context);
String newName = StringUtil.isolateBidi(ProfileName.fromSerialized(profileChangeDetails.getProfileNameChange().getNew()).toString());
String previousName = StringUtil.isolateBidi(ProfileName.fromSerialized(profileChangeDetails.getProfileNameChange().getPrevious()).toString());
String newName = StringUtil.isolateBidi(ProfileName.fromSerialized(profileChangeDetails.profileNameChange.newValue).toString());
String previousName = StringUtil.isolateBidi(ProfileName.fromSerialized(profileChangeDetails.profileNameChange.previous).toString());
if (getFromRecipient().isSystemContact()) {
return context.getString(R.string.MessageRecord_changed_their_profile_name_from_to, displayName, previousName, newName);
@@ -440,7 +441,7 @@ public abstract class MessageRecord extends DisplayRecord {
public static @NonNull UpdateDescription getGroupCallUpdateDescription(@NonNull Context context, @NonNull String body, boolean withTime) {
GroupCallUpdateDetails groupCallUpdateDetails = GroupCallUpdateDetailsUtil.parse(body);
List<ACI> joinedMembers = Stream.of(groupCallUpdateDetails.getInCallUuidsList())
List<ACI> joinedMembers = Stream.of(groupCallUpdateDetails.inCallUuids)
.map(UuidUtil::parseOrNull)
.withoutNulls()
.map(ACI::from)
@@ -454,15 +455,15 @@ public abstract class MessageRecord extends DisplayRecord {
public boolean isGroupV2DescriptionUpdate() {
DecryptedGroupV2Context decryptedGroupV2Context = getDecryptedGroupV2Context();
if (decryptedGroupV2Context != null) {
return decryptedGroupV2Context.hasChange() && getDecryptedGroupV2Context().getChange().hasNewDescription();
return decryptedGroupV2Context.change != null && decryptedGroupV2Context.change.newDescription != null;
}
return false;
}
public @NonNull String getGroupV2DescriptionUpdate() {
DecryptedGroupV2Context decryptedGroupV2Context = getDecryptedGroupV2Context();
if (decryptedGroupV2Context != null) {
return decryptedGroupV2Context.getChange().hasNewDescription() ? decryptedGroupV2Context.getChange().getNewDescription().getValue() : "";
if (decryptedGroupV2Context != null && decryptedGroupV2Context.change != null) {
return decryptedGroupV2Context.change.newDescription != null ? decryptedGroupV2Context.change.newDescription.value_ : "";
}
return "";
}
@@ -474,11 +475,11 @@ public abstract class MessageRecord extends DisplayRecord {
DecryptedGroupV2Context decryptedGroupV2Context = getDecryptedGroupV2Context();
if (decryptedGroupV2Context != null && decryptedGroupV2Context.hasChange()) {
DecryptedGroupChange change = decryptedGroupV2Context.getChange();
if (decryptedGroupV2Context != null && decryptedGroupV2Context.change != null) {
DecryptedGroupChange change = decryptedGroupV2Context.change;
ByteString serviceIdByteString = serviceId.toByteString();
return change.getEditorServiceIdBytes().equals(serviceIdByteString) && change.getNewRequestingMembersList().stream().anyMatch(r -> r.getAciBytes().equals(serviceIdByteString));
return change.editorServiceIdBytes.equals(serviceIdByteString) && change.newRequestingMembers.stream().anyMatch(r -> r.aciBytes.equals(serviceIdByteString));
}
return false;
}
@@ -489,11 +490,11 @@ public abstract class MessageRecord extends DisplayRecord {
public boolean isCollapsedGroupV2JoinUpdate(@Nullable ServiceId serviceId) {
DecryptedGroupV2Context decryptedGroupV2Context = getDecryptedGroupV2Context();
if (decryptedGroupV2Context != null && decryptedGroupV2Context.hasChange()) {
DecryptedGroupChange change = decryptedGroupV2Context.getChange();
return change.getNewRequestingMembersCount() > 0 &&
change.getDeleteRequestingMembersCount() > 0 &&
(serviceId == null || change.getEditorServiceIdBytes().equals(serviceId.toByteString()));
if (decryptedGroupV2Context != null && decryptedGroupV2Context.change != null) {
DecryptedGroupChange change = decryptedGroupV2Context.change;
return change.newRequestingMembers.size() > 0 &&
change.deleteRequestingMembers.size() > 0 &&
(serviceId == null || change.editorServiceIdBytes.equals(serviceId.toByteString()));
}
return false;
}
@@ -501,14 +502,19 @@ public abstract class MessageRecord extends DisplayRecord {
public static @NonNull String createNewContextWithAppendedDeleteJoinRequest(@NonNull MessageRecord messageRecord, int revision, @NonNull ByteString id) {
DecryptedGroupV2Context decryptedGroupV2Context = messageRecord.getDecryptedGroupV2Context();
if (decryptedGroupV2Context != null && decryptedGroupV2Context.hasChange()) {
DecryptedGroupChange change = decryptedGroupV2Context.getChange();
if (decryptedGroupV2Context != null && decryptedGroupV2Context.change != null) {
DecryptedGroupChange change = decryptedGroupV2Context.change;
return Base64.encodeBytes(decryptedGroupV2Context.toBuilder()
.setChange(change.toBuilder()
.setRevision(revision)
.addDeleteRequestingMembers(id))
.build().toByteArray());
List<ByteString> deleteRequestingMembers = new ArrayList<>(change.deleteRequestingMembers);
deleteRequestingMembers.add(id);
return Base64.encodeBytes(decryptedGroupV2Context.newBuilder()
.change(change.newBuilder()
.revision(revision)
.deleteRequestingMembers(deleteRequestingMembers)
.build())
.build()
.encode());
}
throw new AssertionError("Attempting to modify a message with no change");
@@ -553,10 +559,6 @@ public abstract class MessageRecord extends DisplayRecord {
return MessageTypes.isBundleKeyExchange(type);
}
public boolean isContentBundleKeyExchange() {
return MessageTypes.isContentBundleKeyExchange(type);
}
public boolean isRateLimited() {
return MessageTypes.isRateLimited(type);
}
@@ -565,10 +567,6 @@ public abstract class MessageRecord extends DisplayRecord {
return MessageTypes.isIdentityUpdate(type);
}
public boolean isCorruptedKeyExchange() {
return MessageTypes.isCorruptedKeyExchange(type);
}
public boolean isBadDecryptType() {
return MessageTypes.isBadDecryptType(type);
}
@@ -585,10 +583,6 @@ public abstract class MessageRecord extends DisplayRecord {
return MessageTypes.isSmsExport(type);
}
public boolean isInvalidVersionKeyExchange() {
return MessageTypes.isInvalidVersionKeyExchange(type);
}
public boolean isGroupV1MigrationEvent() {
return MessageTypes.isGroupV1MigrationEvent(type);
}
@@ -654,8 +648,7 @@ public abstract class MessageRecord extends DisplayRecord {
}
public boolean equals(Object other) {
return other != null &&
other instanceof MessageRecord &&
return other instanceof MessageRecord &&
((MessageRecord) other).getId() == getId() &&
((MessageRecord) other).isMms() == isMms();
}