mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-04-28 20:54:38 +01:00
Convert SignalService, Database, Group, Payment, and other remaining protos to wire.
This commit is contained in:
committed by
Alex Hart
parent
a6b7d0bcc5
commit
efbd5cab85
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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) }
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -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!")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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!!)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user