mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-04-21 00:59:49 +01:00
Move to defined from_recipient_id and to_recipient_id columns on message table.
This commit is contained in:
committed by
Cody Henthorne
parent
d079f85eca
commit
279ad7945e
@@ -88,7 +88,7 @@ class CallTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTabl
|
||||
val messageType: Long = Call.getMessageType(type, direction, event)
|
||||
|
||||
writableDatabase.withinTransaction {
|
||||
val result = SignalDatabase.messages.insertCallLog(peer, messageType, timestamp)
|
||||
val result = SignalDatabase.messages.insertCallLog(peer, messageType, timestamp, direction == Direction.OUTGOING)
|
||||
|
||||
val values = contentValuesOf(
|
||||
CALL_ID to callId,
|
||||
|
||||
@@ -9,35 +9,30 @@ import org.thoughtcrime.securesms.util.LRUCache;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class EarlyReceiptCache {
|
||||
public class EarlyDeliveryReceiptCache {
|
||||
|
||||
private static final String TAG = Log.tag(EarlyReceiptCache.class);
|
||||
private static final String TAG = Log.tag(EarlyDeliveryReceiptCache.class);
|
||||
|
||||
private final LRUCache<Long, Map<RecipientId, Receipt>> cache = new LRUCache<>(100);
|
||||
private final String name;
|
||||
|
||||
public EarlyReceiptCache(@NonNull String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public synchronized void increment(long timestamp, @NonNull RecipientId origin, long receiptTimestamp) {
|
||||
Map<RecipientId, Receipt> receipts = cache.get(timestamp);
|
||||
public synchronized void increment(long targetTimestamp, @NonNull RecipientId receiptAuthor, long receiptSentTimestamp) {
|
||||
Map<RecipientId, Receipt> receipts = cache.get(targetTimestamp);
|
||||
|
||||
if (receipts == null) {
|
||||
receipts = new HashMap<>();
|
||||
}
|
||||
|
||||
Receipt receipt = receipts.get(origin);
|
||||
Receipt receipt = receipts.get(receiptAuthor);
|
||||
|
||||
if (receipt != null) {
|
||||
receipt.count++;
|
||||
receipt.timestamp = receiptTimestamp;
|
||||
receipt.timestamp = receiptSentTimestamp;
|
||||
} else {
|
||||
receipt = new Receipt(1, receiptTimestamp);
|
||||
receipt = new Receipt(1, receiptSentTimestamp);
|
||||
}
|
||||
receipts.put(origin, receipt);
|
||||
receipts.put(receiptAuthor, receipt);
|
||||
|
||||
cache.put(timestamp, receipts);
|
||||
cache.put(targetTimestamp, receipts);
|
||||
}
|
||||
|
||||
public synchronized Map<RecipientId, Receipt> remove(long timestamp) {
|
||||
@@ -45,7 +40,7 @@ public class EarlyReceiptCache {
|
||||
return receipts != null ? receipts : new HashMap<>();
|
||||
}
|
||||
|
||||
public class Receipt {
|
||||
public static class Receipt {
|
||||
private long count;
|
||||
private long timestamp;
|
||||
|
||||
@@ -1275,7 +1275,7 @@ class GroupTable(context: Context?, databaseHelper: SignalDatabase?) : DatabaseT
|
||||
SELECT ${MessageTable.TABLE_NAME}.${MessageTable.DATE_RECEIVED}
|
||||
FROM ${MessageTable.TABLE_NAME}
|
||||
WHERE
|
||||
${MessageTable.TABLE_NAME}.${MessageTable.RECIPIENT_ID} = ${ThreadTable.TABLE_NAME}.${ThreadTable.RECIPIENT_ID} AND
|
||||
${MessageTable.TABLE_NAME}.${MessageTable.FROM_RECIPIENT_ID} = ${ThreadTable.TABLE_NAME}.${ThreadTable.RECIPIENT_ID} AND
|
||||
${MessageTable.STORY_TYPE} > 1
|
||||
ORDER BY ${MessageTable.TABLE_NAME}.${MessageTable.DATE_RECEIVED} DESC
|
||||
LIMIT 1
|
||||
|
||||
@@ -54,7 +54,7 @@ class MediaTable internal constructor(context: Context?, databaseHelper: SignalD
|
||||
${MessageTable.TABLE_NAME}.${MessageTable.DATE_RECEIVED},
|
||||
${MessageTable.TABLE_NAME}.${MessageTable.DATE_SERVER},
|
||||
${MessageTable.TABLE_NAME}.${MessageTable.THREAD_ID},
|
||||
${MessageTable.TABLE_NAME}.${MessageTable.RECIPIENT_ID},
|
||||
${MessageTable.TABLE_NAME}.${MessageTable.FROM_RECIPIENT_ID},
|
||||
${ThreadTable.TABLE_NAME}.${ThreadTable.RECIPIENT_ID} as $THREAD_RECIPIENT_ID
|
||||
FROM
|
||||
${AttachmentTable.TABLE_NAME}
|
||||
@@ -78,7 +78,7 @@ class MediaTable internal constructor(context: Context?, databaseHelper: SignalD
|
||||
)
|
||||
) AND
|
||||
${AttachmentTable.STICKER_PACK_ID} IS NULL AND
|
||||
${MessageTable.TABLE_NAME}.${MessageTable.RECIPIENT_ID} > 0 AND
|
||||
${MessageTable.TABLE_NAME}.${MessageTable.FROM_RECIPIENT_ID} > 0 AND
|
||||
$THREAD_RECIPIENT_ID > 0
|
||||
""".toSingleLine()
|
||||
|
||||
@@ -204,7 +204,7 @@ class MediaTable internal constructor(context: Context?, databaseHelper: SignalD
|
||||
|
||||
return MediaRecord(
|
||||
attachment = if (attachments.isNotEmpty()) attachments[0] else null,
|
||||
recipientId = RecipientId.from(cursor.requireLong(MessageTable.RECIPIENT_ID)),
|
||||
recipientId = RecipientId.from(cursor.requireLong(MessageTable.FROM_RECIPIENT_ID)),
|
||||
threadId = cursor.requireLong(MessageTable.THREAD_ID),
|
||||
threadRecipientId = RecipientId.from(cursor.requireLong(THREAD_RECIPIENT_ID)),
|
||||
date = if (MessageTypes.isPushType(cursor.requireLong(MessageTable.TYPE))) {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -63,7 +63,7 @@ class SearchTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa
|
||||
private const val MESSAGES_QUERY = """
|
||||
SELECT
|
||||
${ThreadTable.TABLE_NAME}.${ThreadTable.RECIPIENT_ID} AS $CONVERSATION_RECIPIENT,
|
||||
${MessageTable.TABLE_NAME}.${MessageTable.RECIPIENT_ID} AS $MESSAGE_RECIPIENT,
|
||||
${MessageTable.TABLE_NAME}.${MessageTable.FROM_RECIPIENT_ID} AS $MESSAGE_RECIPIENT,
|
||||
snippet($FTS_TABLE_NAME, -1, '', '', '$SNIPPET_WRAP', 7) AS $SNIPPET,
|
||||
${MessageTable.TABLE_NAME}.${MessageTable.DATE_RECEIVED},
|
||||
$FTS_TABLE_NAME.$THREAD_ID,
|
||||
@@ -86,7 +86,7 @@ class SearchTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa
|
||||
private const val MESSAGES_FOR_THREAD_QUERY = """
|
||||
SELECT
|
||||
${ThreadTable.TABLE_NAME}.${ThreadTable.RECIPIENT_ID} AS $CONVERSATION_RECIPIENT,
|
||||
${MessageTable.TABLE_NAME}.${MessageTable.RECIPIENT_ID} AS $MESSAGE_RECIPIENT,
|
||||
${MessageTable.TABLE_NAME}.${MessageTable.FROM_RECIPIENT_ID} AS $MESSAGE_RECIPIENT,
|
||||
snippet($FTS_TABLE_NAME, -1, '', '', '$SNIPPET_WRAP', 7) AS $SNIPPET,
|
||||
${MessageTable.TABLE_NAME}.${MessageTable.DATE_RECEIVED},
|
||||
$FTS_TABLE_NAME.$THREAD_ID,
|
||||
|
||||
@@ -171,14 +171,14 @@ class StorySendTable(context: Context, databaseHelper: SignalDatabase) : Databas
|
||||
}
|
||||
}
|
||||
|
||||
fun getStoryMessagesFor(syncMessageId: MessageTable.SyncMessageId): Set<MessageId> {
|
||||
fun getStoryMessagesFor(recipientId: RecipientId, sentTimestamp: Long): Set<MessageId> {
|
||||
val messageIds = mutableSetOf<MessageId>()
|
||||
|
||||
readableDatabase.query(
|
||||
TABLE_NAME,
|
||||
arrayOf(MESSAGE_ID),
|
||||
"$RECIPIENT_ID = ? AND $SENT_TIMESTAMP = ?",
|
||||
SqlUtil.buildArgs(syncMessageId.recipientId, syncMessageId.timetamp),
|
||||
SqlUtil.buildArgs(recipientId, sentTimestamp),
|
||||
null,
|
||||
null,
|
||||
null
|
||||
@@ -270,7 +270,7 @@ class StorySendTable(context: Context, databaseHelper: SignalDatabase) : Databas
|
||||
val query = """
|
||||
SELECT ${MessageTable.TABLE_NAME}.${MessageTable.ID} as $MESSAGE_ID, ${DistributionListTables.DISTRIBUTION_ID}
|
||||
FROM ${MessageTable.TABLE_NAME}
|
||||
INNER JOIN ${DistributionListTables.LIST_TABLE_NAME} ON ${DistributionListTables.LIST_TABLE_NAME}.${DistributionListTables.RECIPIENT_ID} = ${MessageTable.TABLE_NAME}.${MessageTable.RECIPIENT_ID}
|
||||
INNER JOIN ${DistributionListTables.LIST_TABLE_NAME} ON ${DistributionListTables.LIST_TABLE_NAME}.${DistributionListTables.RECIPIENT_ID} = ${MessageTable.TABLE_NAME}.${MessageTable.TO_RECIPIENT_ID}
|
||||
WHERE ${MessageTable.DATE_SENT} = $sentTimestamp AND ${DistributionListTables.DISTRIBUTION_ID} IS NOT NULL
|
||||
""".trimIndent()
|
||||
|
||||
|
||||
@@ -91,11 +91,11 @@ public final class ThreadBodyUtil {
|
||||
|
||||
private static @NonNull String getGiftSummary(@NonNull Context context, @NonNull MessageRecord messageRecord) {
|
||||
if (messageRecord.isOutgoing()) {
|
||||
return context.getString(R.string.ThreadRecord__you_donated_for_s, messageRecord.getRecipient().getShortDisplayName(context));
|
||||
return context.getString(R.string.ThreadRecord__you_donated_for_s, messageRecord.getToRecipient().getShortDisplayName(context));
|
||||
} else if (messageRecord.getViewedReceiptCount() > 0) {
|
||||
return context.getString(R.string.ThreadRecord__you_redeemed_a_badge);
|
||||
} else {
|
||||
return context.getString(R.string.ThreadRecord__s_donated_for_you, messageRecord.getRecipient().getShortDisplayName(context));
|
||||
return context.getString(R.string.ThreadRecord__s_donated_for_you, messageRecord.getFromRecipient().getShortDisplayName(context));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,7 +111,7 @@ public final class ThreadBodyUtil {
|
||||
if (messageRecord.isOutgoing()) {
|
||||
return context.getString(R.string.ThreadRecord_you_sent_request);
|
||||
} else {
|
||||
return context.getString(R.string.ThreadRecord_wants_you_to_activate_payments, messageRecord.getRecipient().getShortDisplayName(context));
|
||||
return context.getString(R.string.ThreadRecord_wants_you_to_activate_payments, messageRecord.getFromRecipient().getShortDisplayName(context));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -119,7 +119,7 @@ public final class ThreadBodyUtil {
|
||||
if (messageRecord.isOutgoing()) {
|
||||
return context.getString(R.string.ThreadRecord_you_activated_payments);
|
||||
} else {
|
||||
return context.getString(R.string.ThreadRecord_can_accept_payments, messageRecord.getRecipient().getShortDisplayName(context));
|
||||
return context.getString(R.string.ThreadRecord_can_accept_payments, messageRecord.getFromRecipient().getShortDisplayName(context));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1359,6 +1359,11 @@ class ThreadTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa
|
||||
}
|
||||
|
||||
private fun update(threadId: Long, unarchive: Boolean, allowDeletion: Boolean, notifyListeners: Boolean): Boolean {
|
||||
if (threadId == -1L) {
|
||||
Log.d(TAG, "Skipping update for threadId -1")
|
||||
return false
|
||||
}
|
||||
|
||||
val meaningfulMessages = messages.hasMeaningfulMessage(threadId)
|
||||
|
||||
val isPinned = getPinnedThreadIds().contains(threadId)
|
||||
@@ -1581,10 +1586,10 @@ class ThreadTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa
|
||||
}
|
||||
|
||||
private fun getExtrasFor(record: MessageRecord, body: ThreadBody): Extra? {
|
||||
val threadRecipient = if (record.isOutgoing) record.recipient else getRecipientForThreadId(record.threadId)
|
||||
val threadRecipient = getRecipientForThreadId(record.threadId)
|
||||
val messageRequestAccepted = RecipientUtil.isMessageRequestAccepted(record.threadId, threadRecipient)
|
||||
val isHidden = threadRecipient?.isHidden ?: false
|
||||
val individualRecipientId = record.individualRecipient.id
|
||||
val authorId = record.fromRecipient.id
|
||||
|
||||
if (!messageRequestAccepted && threadRecipient != null) {
|
||||
if (threadRecipient.isPushGroup) {
|
||||
@@ -1594,46 +1599,46 @@ class ThreadTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa
|
||||
val from = RecipientId.from(ServiceId.from(inviteAddState.addedOrInvitedBy))
|
||||
return if (inviteAddState.isInvited) {
|
||||
Log.i(TAG, "GV2 invite message request from $from")
|
||||
Extra.forGroupV2invite(from, individualRecipientId)
|
||||
Extra.forGroupV2invite(from, authorId)
|
||||
} else {
|
||||
Log.i(TAG, "GV2 message request from $from")
|
||||
Extra.forGroupMessageRequest(from, individualRecipientId)
|
||||
Extra.forGroupMessageRequest(from, authorId)
|
||||
}
|
||||
}
|
||||
|
||||
Log.w(TAG, "Falling back to unknown message request state for GV2 message")
|
||||
return Extra.forMessageRequest(individualRecipientId)
|
||||
return Extra.forMessageRequest(authorId)
|
||||
} else {
|
||||
val recipientId = messages.getGroupAddedBy(record.threadId)
|
||||
if (recipientId != null) {
|
||||
return Extra.forGroupMessageRequest(recipientId, individualRecipientId)
|
||||
return Extra.forGroupMessageRequest(recipientId, authorId)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return Extra.forMessageRequest(individualRecipientId, isHidden)
|
||||
return Extra.forMessageRequest(authorId, isHidden)
|
||||
}
|
||||
}
|
||||
|
||||
val extras: Extra? = if (record.isScheduled()) {
|
||||
Extra.forScheduledMessage(individualRecipientId)
|
||||
Extra.forScheduledMessage(authorId)
|
||||
} else if (record.isRemoteDelete) {
|
||||
Extra.forRemoteDelete(individualRecipientId)
|
||||
Extra.forRemoteDelete(authorId)
|
||||
} else if (record.isViewOnce) {
|
||||
Extra.forViewOnce(individualRecipientId)
|
||||
Extra.forViewOnce(authorId)
|
||||
} else if (record.isMms && (record as MmsMessageRecord).slideDeck.stickerSlide != null) {
|
||||
val slide: StickerSlide = record.slideDeck.stickerSlide!!
|
||||
Extra.forSticker(slide.emoji, individualRecipientId)
|
||||
Extra.forSticker(slide.emoji, authorId)
|
||||
} else if (record.isMms && (record as MmsMessageRecord).slideDeck.slides.size > 1) {
|
||||
Extra.forAlbum(individualRecipientId)
|
||||
Extra.forAlbum(authorId)
|
||||
} else if (threadRecipient != null && threadRecipient.isGroup) {
|
||||
Extra.forDefault(individualRecipientId)
|
||||
Extra.forDefault(authorId)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
|
||||
return if (record.messageRanges != null) {
|
||||
val bodyRanges = record.requireMessageRanges().adjustBodyRanges(body.bodyAdjustments)!!
|
||||
extras?.copy(bodyRanges = bodyRanges.serialize()) ?: Extra.forBodyRanges(bodyRanges, individualRecipientId)
|
||||
extras?.copy(bodyRanges = bodyRanges.serialize()) ?: Extra.forBodyRanges(bodyRanges, authorId)
|
||||
} else {
|
||||
extras
|
||||
}
|
||||
|
||||
@@ -40,6 +40,7 @@ import org.thoughtcrime.securesms.database.helpers.migration.V181_ThreadTableFor
|
||||
import org.thoughtcrime.securesms.database.helpers.migration.V182_CallTableMigration
|
||||
import org.thoughtcrime.securesms.database.helpers.migration.V183_CallLinkTableMigration
|
||||
import org.thoughtcrime.securesms.database.helpers.migration.V184_CallLinkReplaceIndexMigration
|
||||
import org.thoughtcrime.securesms.database.helpers.migration.V185_MessageRecipientsMigration
|
||||
|
||||
/**
|
||||
* Contains all of the database migrations for [SignalDatabase]. Broken into a separate file for cleanliness.
|
||||
@@ -48,7 +49,7 @@ object SignalDatabaseMigrations {
|
||||
|
||||
val TAG: String = Log.tag(SignalDatabaseMigrations.javaClass)
|
||||
|
||||
const val DATABASE_VERSION = 184
|
||||
const val DATABASE_VERSION = 185
|
||||
|
||||
@JvmStatic
|
||||
fun migrate(context: Application, db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
|
||||
@@ -195,6 +196,10 @@ object SignalDatabaseMigrations {
|
||||
if (oldVersion < 184) {
|
||||
V184_CallLinkReplaceIndexMigration.migrate(context, db, oldVersion, newVersion)
|
||||
}
|
||||
|
||||
if (oldVersion < 185) {
|
||||
V185_MessageRecipientsMigration.migrate(context, db, oldVersion, newVersion)
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
|
||||
@@ -0,0 +1,285 @@
|
||||
package org.thoughtcrime.securesms.database.helpers.migration
|
||||
|
||||
import android.app.Application
|
||||
import android.preference.PreferenceManager
|
||||
import net.zetetic.database.sqlcipher.SQLiteDatabase
|
||||
import org.signal.core.util.SqlUtil
|
||||
import org.signal.core.util.Stopwatch
|
||||
import org.signal.core.util.logging.Log
|
||||
import org.signal.core.util.readToList
|
||||
import org.signal.core.util.readToSingleInt
|
||||
import org.signal.core.util.readToSingleObject
|
||||
import org.signal.core.util.requireLong
|
||||
import org.signal.core.util.requireNonNullString
|
||||
import org.signal.core.util.requireString
|
||||
import org.signal.core.util.toSingleLine
|
||||
import org.thoughtcrime.securesms.database.KeyValueDatabase
|
||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId
|
||||
import org.whispersystems.signalservice.api.push.ACI
|
||||
|
||||
/**
|
||||
* Our current column setup for knowing is the the sender/receiver of a message is both confusing and non-optimal from a performance perspective.
|
||||
* This moves to a world where instead of tracking a single recipient, we track two: a sender and receiver.
|
||||
*/
|
||||
object V185_MessageRecipientsMigration : SignalDatabaseMigration {
|
||||
|
||||
private val TAG = Log.tag(V185_MessageRecipientsMigration::class.java)
|
||||
|
||||
private val outgoingClause = "(" + listOf(21, 23, 22, 24, 25, 26, 2, 11)
|
||||
.map { "type & ${0x1F} = $it" }
|
||||
.joinToString(separator = " OR ") + ")"
|
||||
|
||||
override fun migrate(context: Application, db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
|
||||
val stopwatch = Stopwatch("migration")
|
||||
|
||||
val selfId: RecipientId? = getSelfId(db)
|
||||
|
||||
if (selfId == null) {
|
||||
val messageCount = db.rawQuery("SELECT COUNT(*) FROM message").readToSingleInt()
|
||||
if (messageCount == 0) {
|
||||
Log.i(TAG, "Could not find ourselves in the DB! Assuming this is an install that hasn't been registered yet.")
|
||||
} else {
|
||||
throw IllegalStateException("Could not find ourselves in the recipient table, but messages exist in the message table!")
|
||||
}
|
||||
}
|
||||
|
||||
stopwatch.split("get-self")
|
||||
|
||||
val dependentItems: List<SqlItem> = getAllDependentItems(db, "message")
|
||||
|
||||
dependentItems.forEach { item ->
|
||||
val sql = "DROP ${item.type} IF EXISTS ${item.name}"
|
||||
Log.d(TAG, "Executing: $sql")
|
||||
db.execSQL(sql)
|
||||
}
|
||||
|
||||
stopwatch.split("drop-dependents")
|
||||
|
||||
db.execSQL(
|
||||
"""
|
||||
CREATE TABLE message_tmp (
|
||||
_id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
date_sent INTEGER NOT NULL,
|
||||
date_received INTEGER NOT NULL,
|
||||
date_server INTEGER DEFAULT -1,
|
||||
thread_id INTEGER NOT NULL REFERENCES thread (_id) ON DELETE CASCADE,
|
||||
from_recipient_id INTEGER NOT NULL REFERENCES recipient (_id) ON DELETE CASCADE,
|
||||
from_device_id INTEGER,
|
||||
to_recipient_id INTEGER NOT NULL REFERENCES recipient (_id) ON DELETE CASCADE,
|
||||
type INTEGER NOT NULL,
|
||||
body TEXT,
|
||||
read INTEGER DEFAULT 0,
|
||||
ct_l TEXT,
|
||||
exp INTEGER,
|
||||
m_type INTEGER,
|
||||
m_size INTEGER,
|
||||
st INTEGER,
|
||||
tr_id TEXT,
|
||||
subscription_id INTEGER DEFAULT -1,
|
||||
receipt_timestamp INTEGER DEFAULT -1,
|
||||
delivery_receipt_count INTEGER DEFAULT 0,
|
||||
read_receipt_count INTEGER DEFAULT 0,
|
||||
viewed_receipt_count INTEGER DEFAULT 0,
|
||||
mismatched_identities TEXT DEFAULT NULL,
|
||||
network_failures TEXT DEFAULT NULL,
|
||||
expires_in INTEGER DEFAULT 0,
|
||||
expire_started INTEGER DEFAULT 0,
|
||||
notified INTEGER DEFAULT 0,
|
||||
quote_id INTEGER DEFAULT 0,
|
||||
quote_author INTEGER DEFAULT 0,
|
||||
quote_body TEXT DEFAULT NULL,
|
||||
quote_missing INTEGER DEFAULT 0,
|
||||
quote_mentions BLOB DEFAULT NULL,
|
||||
quote_type INTEGER DEFAULT 0,
|
||||
shared_contacts TEXT DEFAULT NULL,
|
||||
unidentified INTEGER DEFAULT 0,
|
||||
link_previews TEXT DEFAULT NULL,
|
||||
view_once INTEGER DEFAULT 0,
|
||||
reactions_unread INTEGER DEFAULT 0,
|
||||
reactions_last_seen INTEGER DEFAULT -1,
|
||||
remote_deleted INTEGER DEFAULT 0,
|
||||
mentions_self INTEGER DEFAULT 0,
|
||||
notified_timestamp INTEGER DEFAULT 0,
|
||||
server_guid TEXT DEFAULT NULL,
|
||||
message_ranges BLOB DEFAULT NULL,
|
||||
story_type INTEGER DEFAULT 0,
|
||||
parent_story_id INTEGER DEFAULT 0,
|
||||
export_state BLOB DEFAULT NULL,
|
||||
exported INTEGER DEFAULT 0,
|
||||
scheduled_date INTEGER DEFAULT -1
|
||||
)
|
||||
"""
|
||||
)
|
||||
stopwatch.split("create-table")
|
||||
|
||||
db.execSQL(
|
||||
"""
|
||||
INSERT INTO message_tmp
|
||||
SELECT
|
||||
_id,
|
||||
date_sent,
|
||||
date_received,
|
||||
date_server,
|
||||
thread_id,
|
||||
recipient_id,
|
||||
recipient_device_id,
|
||||
recipient_id,
|
||||
type,
|
||||
body,
|
||||
read,
|
||||
ct_l,
|
||||
exp,
|
||||
m_type,
|
||||
m_size,
|
||||
st,
|
||||
tr_id,
|
||||
subscription_id,
|
||||
receipt_timestamp,
|
||||
delivery_receipt_count,
|
||||
read_receipt_count,
|
||||
viewed_receipt_count,
|
||||
mismatched_identities,
|
||||
network_failures,
|
||||
expires_in,
|
||||
expire_started,
|
||||
notified,
|
||||
quote_id,
|
||||
quote_author,
|
||||
quote_body,
|
||||
quote_missing,
|
||||
quote_mentions,
|
||||
quote_type,
|
||||
shared_contacts,
|
||||
unidentified,
|
||||
link_previews,
|
||||
view_once,
|
||||
reactions_unread,
|
||||
reactions_last_seen,
|
||||
remote_deleted,
|
||||
mentions_self,
|
||||
notified_timestamp,
|
||||
server_guid,
|
||||
message_ranges,
|
||||
story_type,
|
||||
parent_story_id,
|
||||
export_state,
|
||||
exported,
|
||||
scheduled_date
|
||||
FROM message
|
||||
"""
|
||||
)
|
||||
stopwatch.split("copy-data")
|
||||
|
||||
// Previously, the recipient_id on an outgoing message represented who it was going to (an individual or group).
|
||||
// So if a message is outgoing, we'll set to = from, then from = self
|
||||
if (selfId != null) {
|
||||
db.execSQL(
|
||||
"""
|
||||
UPDATE message_tmp
|
||||
SET
|
||||
to_recipient_id = from_recipient_id,
|
||||
from_recipient_id = ${selfId.toLong()},
|
||||
from_device_id = 1
|
||||
WHERE $outgoingClause
|
||||
""".toSingleLine()
|
||||
)
|
||||
}
|
||||
stopwatch.split("update-data")
|
||||
|
||||
db.execSQL("DROP TABLE message")
|
||||
stopwatch.split("drop-old-table")
|
||||
|
||||
db.execSQL("ALTER TABLE message_tmp RENAME TO message")
|
||||
stopwatch.split("rename-table")
|
||||
|
||||
dependentItems.forEach { item ->
|
||||
val sql = when (item.name) {
|
||||
"mms_date_sent_index" -> "CREATE INDEX message_date_sent_from_to_thread_index ON message (date_sent, from_recipient_id, to_recipient_id, thread_id)"
|
||||
else -> item.createStatement.replace(Regex.fromLiteral("CREATE INDEX mms_"), "CREATE INDEX message_")
|
||||
}
|
||||
Log.d(TAG, "Executing: $sql")
|
||||
db.execSQL(sql)
|
||||
}
|
||||
stopwatch.split("recreate-dependents")
|
||||
|
||||
db.execSQL("PRAGMA foreign_key_check")
|
||||
stopwatch.split("fk-check")
|
||||
|
||||
stopwatch.stop(TAG)
|
||||
}
|
||||
|
||||
private fun getSelfId(db: SQLiteDatabase): RecipientId? {
|
||||
val idByAci: RecipientId? = getLocalAci(ApplicationDependencies.getApplication())?.let { aci ->
|
||||
db.rawQuery("SELECT _id FROM recipient WHERE uuid = ?", SqlUtil.buildArgs(aci))
|
||||
.readToSingleObject { RecipientId.from(it.requireLong("_id")) }
|
||||
}
|
||||
|
||||
if (idByAci != null) {
|
||||
return idByAci
|
||||
}
|
||||
|
||||
Log.w(TAG, "Failed to find by ACI! Will try by E164.")
|
||||
|
||||
val idByE164: RecipientId? = getLocalE164(ApplicationDependencies.getApplication())?.let { e164 ->
|
||||
db.rawQuery("SELECT _id FROM recipient WHERE phone = ?", SqlUtil.buildArgs(e164))
|
||||
.readToSingleObject { RecipientId.from(it.requireLong("_id")) }
|
||||
}
|
||||
|
||||
if (idByE164 == null) {
|
||||
Log.w(TAG, "Also failed to find by E164!")
|
||||
}
|
||||
|
||||
return idByE164
|
||||
}
|
||||
|
||||
private fun getLocalAci(context: Application): ACI? {
|
||||
if (KeyValueDatabase.exists(context)) {
|
||||
val keyValueDatabase = KeyValueDatabase.getInstance(context).readableDatabase
|
||||
keyValueDatabase.query("key_value", arrayOf("value"), "key = ?", SqlUtil.buildArgs("account.aci"), null, null, null).use { cursor ->
|
||||
return if (cursor.moveToFirst()) {
|
||||
ACI.parseOrNull(cursor.requireString("value"))
|
||||
} else {
|
||||
Log.w(TAG, "ACI not present in KV database!")
|
||||
null
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Log.w(TAG, "Pre-KV database -- searching for ACI in shared prefs.")
|
||||
return ACI.parseOrNull(PreferenceManager.getDefaultSharedPreferences(context).getString("pref_local_uuid", null))
|
||||
}
|
||||
}
|
||||
|
||||
private fun getLocalE164(context: Application): String? {
|
||||
if (KeyValueDatabase.exists(context)) {
|
||||
val keyValueDatabase = KeyValueDatabase.getInstance(context).readableDatabase
|
||||
keyValueDatabase.query("key_value", arrayOf("value"), "key = ?", SqlUtil.buildArgs("account.e164"), null, null, null).use { cursor ->
|
||||
return if (cursor.moveToFirst()) {
|
||||
cursor.requireString("value")
|
||||
} else {
|
||||
Log.w(TAG, "E164 not present in KV database!")
|
||||
null
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Log.w(TAG, "Pre-KV database -- searching for E164 in shared prefs.")
|
||||
return PreferenceManager.getDefaultSharedPreferences(context).getString("pref_local_number", null)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getAllDependentItems(db: SQLiteDatabase, tableName: String): List<SqlItem> {
|
||||
return db.rawQuery("SELECT type, name, sql FROM sqlite_schema WHERE tbl_name='$tableName' AND type != 'table'").readToList { cursor ->
|
||||
SqlItem(
|
||||
type = cursor.requireNonNullString("type"),
|
||||
name = cursor.requireNonNullString("name"),
|
||||
createStatement = cursor.requireNonNullString("sql")
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
data class SqlItem(
|
||||
val type: String,
|
||||
val name: String,
|
||||
val createStatement: String
|
||||
)
|
||||
}
|
||||
@@ -39,7 +39,8 @@ public abstract class DisplayRecord {
|
||||
|
||||
protected final long type;
|
||||
|
||||
private final Recipient recipient;
|
||||
private final Recipient fromRecipient;
|
||||
private final Recipient toRecipient;
|
||||
private final long dateSent;
|
||||
private final long dateReceived;
|
||||
private final long threadId;
|
||||
@@ -49,12 +50,13 @@ public abstract class DisplayRecord {
|
||||
private final int readReceiptCount;
|
||||
private final int viewReceiptCount;
|
||||
|
||||
DisplayRecord(String body, Recipient recipient, long dateSent,
|
||||
DisplayRecord(String body, Recipient fromRecipient, Recipient toRecipient, long dateSent,
|
||||
long dateReceived, long threadId, int deliveryStatus, int deliveryReceiptCount,
|
||||
long type, int readReceiptCount, int viewReceiptCount)
|
||||
{
|
||||
this.threadId = threadId;
|
||||
this.recipient = recipient;
|
||||
this.fromRecipient = fromRecipient;
|
||||
this.toRecipient = toRecipient;
|
||||
this.dateSent = dateSent;
|
||||
this.dateReceived = dateReceived;
|
||||
this.type = type;
|
||||
@@ -97,8 +99,12 @@ public abstract class DisplayRecord {
|
||||
|
||||
public abstract SpannableString getDisplayBody(@NonNull Context context);
|
||||
|
||||
public Recipient getRecipient() {
|
||||
return recipient.live().get();
|
||||
public Recipient getFromRecipient() {
|
||||
return fromRecipient.live().get();
|
||||
}
|
||||
|
||||
public Recipient getToRecipient() {
|
||||
return toRecipient.live().get();
|
||||
}
|
||||
|
||||
public long getDateSent() {
|
||||
|
||||
@@ -27,15 +27,15 @@ public class InMemoryMessageRecord extends MessageRecord {
|
||||
|
||||
private InMemoryMessageRecord(long id,
|
||||
String body,
|
||||
Recipient conversationRecipient,
|
||||
Recipient author,
|
||||
long threadId,
|
||||
long type)
|
||||
{
|
||||
super(id,
|
||||
body,
|
||||
conversationRecipient,
|
||||
conversationRecipient,
|
||||
author,
|
||||
1,
|
||||
author,
|
||||
System.currentTimeMillis(),
|
||||
System.currentTimeMillis(),
|
||||
System.currentTimeMillis(),
|
||||
@@ -170,8 +170,8 @@ public class InMemoryMessageRecord extends MessageRecord {
|
||||
* Useful for create an empty message record when one is needed.
|
||||
*/
|
||||
public static final class ForceConversationBubble extends InMemoryMessageRecord {
|
||||
public ForceConversationBubble(Recipient conversationRecipient, long threadId) {
|
||||
super(FORCE_BUBBLE_ID, "", conversationRecipient, threadId, 0);
|
||||
public ForceConversationBubble(Recipient author, long threadId) {
|
||||
super(FORCE_BUBBLE_ID, "", author, threadId, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,9 +72,9 @@ public class MediaMmsMessageRecord extends MmsMessageRecord {
|
||||
private final long scheduledDate;
|
||||
|
||||
public MediaMmsMessageRecord(long id,
|
||||
Recipient conversationRecipient,
|
||||
Recipient individualRecipient,
|
||||
int recipientDeviceId,
|
||||
Recipient fromRecipient,
|
||||
int fromDeviceId,
|
||||
Recipient toRecipient,
|
||||
long dateSent,
|
||||
long dateReceived,
|
||||
long dateServer,
|
||||
@@ -108,7 +108,7 @@ public class MediaMmsMessageRecord extends MmsMessageRecord {
|
||||
@Nullable CallTable.Call call,
|
||||
long scheduledDate)
|
||||
{
|
||||
super(id, body, conversationRecipient, individualRecipient, recipientDeviceId, dateSent,
|
||||
super(id, body, fromRecipient, fromDeviceId, toRecipient, dateSent,
|
||||
dateReceived, dateServer, threadId, Status.STATUS_NONE, deliveryReceiptCount, mailbox, mismatches, failures,
|
||||
subscriptionId, expiresIn, expireStarted, viewOnce, slideDeck,
|
||||
readReceiptCount, quote, contacts, linkPreviews, unidentified, reactions, remoteDelete, notifiedTimestamp, viewedReceiptCount, receiptTimestamp,
|
||||
@@ -205,14 +205,14 @@ public class MediaMmsMessageRecord extends MmsMessageRecord {
|
||||
}
|
||||
|
||||
public @NonNull MediaMmsMessageRecord withReactions(@NonNull List<ReactionRecord> reactions) {
|
||||
return new MediaMmsMessageRecord(getId(), getRecipient(), getIndividualRecipient(), getRecipientDeviceId(), getDateSent(), getDateReceived(), getServerTimestamp(), getDeliveryReceiptCount(), getThreadId(), getBody(), getSlideDeck(),
|
||||
return new MediaMmsMessageRecord(getId(), getFromRecipient(), getFromDeviceId(), getToRecipient(), getDateSent(), getDateReceived(), getServerTimestamp(), getDeliveryReceiptCount(), getThreadId(), getBody(), getSlideDeck(),
|
||||
getType(), getIdentityKeyMismatches(), getNetworkFailures(), getSubscriptionId(), getExpiresIn(), getExpireStarted(), isViewOnce(),
|
||||
getReadReceiptCount(), getQuote(), getSharedContacts(), getLinkPreviews(), isUnidentified(), reactions, isRemoteDelete(), mentionsSelf,
|
||||
getNotifiedTimestamp(), getViewedReceiptCount(), getReceiptTimestamp(), getMessageRanges(), getStoryType(), getParentStoryId(), getGiftBadge(), getPayment(), getCall(), getScheduledDate());
|
||||
}
|
||||
|
||||
public @NonNull MediaMmsMessageRecord withoutQuote() {
|
||||
return new MediaMmsMessageRecord(getId(), getRecipient(), getIndividualRecipient(), getRecipientDeviceId(), getDateSent(), getDateReceived(), getServerTimestamp(), getDeliveryReceiptCount(), getThreadId(), getBody(), getSlideDeck(),
|
||||
return new MediaMmsMessageRecord(getId(), getFromRecipient(), getFromDeviceId(), getToRecipient(), getDateSent(), getDateReceived(), getServerTimestamp(), getDeliveryReceiptCount(), getThreadId(), getBody(), getSlideDeck(),
|
||||
getType(), getIdentityKeyMismatches(), getNetworkFailures(), getSubscriptionId(), getExpiresIn(), getExpireStarted(), isViewOnce(),
|
||||
getReadReceiptCount(), null, getSharedContacts(), getLinkPreviews(), isUnidentified(), getReactions(), isRemoteDelete(), mentionsSelf,
|
||||
getNotifiedTimestamp(), getViewedReceiptCount(), getReceiptTimestamp(), getMessageRanges(), getStoryType(), getParentStoryId(), getGiftBadge(), getPayment(), getCall(), getScheduledDate());
|
||||
@@ -233,14 +233,14 @@ public class MediaMmsMessageRecord extends MmsMessageRecord {
|
||||
List<DatabaseAttachment> slideAttachments = attachments.stream().filter(a -> !contactAttachments.contains(a)).filter(a -> !linkPreviewAttachments.contains(a)).collect(Collectors.toList());
|
||||
SlideDeck slideDeck = MessageTable.MmsReader.buildSlideDeck(context, slideAttachments);
|
||||
|
||||
return new MediaMmsMessageRecord(getId(), getRecipient(), getIndividualRecipient(), getRecipientDeviceId(), getDateSent(), getDateReceived(), getServerTimestamp(), getDeliveryReceiptCount(), getThreadId(), getBody(), slideDeck,
|
||||
return new MediaMmsMessageRecord(getId(), getFromRecipient(), getFromDeviceId(), getToRecipient(), getDateSent(), getDateReceived(), getServerTimestamp(), getDeliveryReceiptCount(), getThreadId(), getBody(), slideDeck,
|
||||
getType(), getIdentityKeyMismatches(), getNetworkFailures(), getSubscriptionId(), getExpiresIn(), getExpireStarted(), isViewOnce(),
|
||||
getReadReceiptCount(), quote, contacts, linkPreviews, isUnidentified(), getReactions(), isRemoteDelete(), mentionsSelf,
|
||||
getNotifiedTimestamp(), getViewedReceiptCount(), getReceiptTimestamp(), getMessageRanges(), getStoryType(), getParentStoryId(), getGiftBadge(), getPayment(), getCall(), getScheduledDate());
|
||||
}
|
||||
|
||||
public @NonNull MediaMmsMessageRecord withPayment(@NonNull Payment payment) {
|
||||
return new MediaMmsMessageRecord(getId(), getRecipient(), getIndividualRecipient(), getRecipientDeviceId(), getDateSent(), getDateReceived(), getServerTimestamp(), getDeliveryReceiptCount(), getThreadId(), getBody(), getSlideDeck(),
|
||||
return new MediaMmsMessageRecord(getId(), getFromRecipient(), getFromDeviceId(), getToRecipient(), getDateSent(), getDateReceived(), getServerTimestamp(), getDeliveryReceiptCount(), getThreadId(), getBody(), getSlideDeck(),
|
||||
getType(), getIdentityKeyMismatches(), getNetworkFailures(), getSubscriptionId(), getExpiresIn(), getExpireStarted(), isViewOnce(),
|
||||
getReadReceiptCount(), getQuote(), getSharedContacts(), getLinkPreviews(), isUnidentified(), getReactions(), isRemoteDelete(), mentionsSelf,
|
||||
getNotifiedTimestamp(), getViewedReceiptCount(), getReceiptTimestamp(), getMessageRanges(), getStoryType(), getParentStoryId(), getGiftBadge(), payment, getCall(), getScheduledDate());
|
||||
@@ -248,7 +248,7 @@ public class MediaMmsMessageRecord extends MmsMessageRecord {
|
||||
|
||||
|
||||
public @NonNull MediaMmsMessageRecord withCall(@Nullable CallTable.Call call) {
|
||||
return new MediaMmsMessageRecord(getId(), getRecipient(), getIndividualRecipient(), getRecipientDeviceId(), getDateSent(), getDateReceived(), getServerTimestamp(), getDeliveryReceiptCount(), getThreadId(), getBody(), getSlideDeck(),
|
||||
return new MediaMmsMessageRecord(getId(), getFromRecipient(), getFromDeviceId(), getToRecipient(), getDateSent(), getDateReceived(), getServerTimestamp(), getDeliveryReceiptCount(), getThreadId(), getBody(), getSlideDeck(),
|
||||
getType(), getIdentityKeyMismatches(), getNetworkFailures(), getSubscriptionId(), getExpiresIn(), getExpireStarted(), isViewOnce(),
|
||||
getReadReceiptCount(), getQuote(), getSharedContacts(), getLinkPreviews(), isUnidentified(), getReactions(), isRemoteDelete(), mentionsSelf,
|
||||
getNotifiedTimestamp(), getViewedReceiptCount(), getReceiptTimestamp(), getMessageRanges(), getStoryType(), getParentStoryId(), getGiftBadge(), getPayment(), call, getScheduledDate());
|
||||
|
||||
@@ -89,9 +89,8 @@ public abstract class MessageRecord extends DisplayRecord {
|
||||
|
||||
private static final String TAG = Log.tag(MessageRecord.class);
|
||||
|
||||
private final Recipient individualRecipient;
|
||||
private final int recipientDeviceId;
|
||||
private final long id;
|
||||
private final int authorDeviceId;
|
||||
private final Set<IdentityKeyMismatch> mismatches;
|
||||
private final Set<NetworkFailure> networkFailures;
|
||||
private final int subscriptionId;
|
||||
@@ -106,8 +105,7 @@ public abstract class MessageRecord extends DisplayRecord {
|
||||
|
||||
protected Boolean isJumboji = null;
|
||||
|
||||
MessageRecord(long id, String body, Recipient conversationRecipient,
|
||||
Recipient individualRecipient, int recipientDeviceId,
|
||||
MessageRecord(long id, String body, Recipient fromRecipient, int fromDeviceId, Recipient toRecipient,
|
||||
long dateSent, long dateReceived, long dateServer, long threadId,
|
||||
int deliveryStatus, int deliveryReceiptCount, long type,
|
||||
Set<IdentityKeyMismatch> mismatches,
|
||||
@@ -117,12 +115,11 @@ public abstract class MessageRecord extends DisplayRecord {
|
||||
@NonNull List<ReactionRecord> reactions, boolean remoteDelete, long notifiedTimestamp,
|
||||
int viewedReceiptCount, long receiptTimestamp)
|
||||
{
|
||||
super(body, conversationRecipient, dateSent, dateReceived,
|
||||
super(body, fromRecipient, toRecipient, dateSent, dateReceived,
|
||||
threadId, deliveryStatus, deliveryReceiptCount, type,
|
||||
readReceiptCount, viewedReceiptCount);
|
||||
this.id = id;
|
||||
this.individualRecipient = individualRecipient;
|
||||
this.recipientDeviceId = recipientDeviceId;
|
||||
this.authorDeviceId = fromDeviceId;
|
||||
this.mismatches = mismatches;
|
||||
this.networkFailures = networkFailures;
|
||||
this.subscriptionId = subscriptionId;
|
||||
@@ -171,11 +168,11 @@ public abstract class MessageRecord extends DisplayRecord {
|
||||
} else if (isGroupUpdate() && isOutgoing()) {
|
||||
return staticUpdateDescription(context.getString(R.string.MessageRecord_you_updated_group), R.drawable.ic_update_group_16);
|
||||
} else if (isGroupUpdate()) {
|
||||
return fromRecipient(getIndividualRecipient(), r -> GroupUtil.getNonV2GroupDescription(context, getBody()).toString(r), R.drawable.ic_update_group_16);
|
||||
return fromRecipient(getFromRecipient(), r -> GroupUtil.getNonV2GroupDescription(context, getBody()).toString(r), R.drawable.ic_update_group_16);
|
||||
} else if (isGroupQuit() && isOutgoing()) {
|
||||
return staticUpdateDescription(context.getString(R.string.MessageRecord_left_group), R.drawable.ic_update_group_leave_16);
|
||||
} else if (isGroupQuit()) {
|
||||
return fromRecipient(getIndividualRecipient(), r -> context.getString(R.string.ConversationItem_group_action_left, r.getDisplayName(context)), R.drawable.ic_update_group_leave_16);
|
||||
return fromRecipient(getFromRecipient(), r -> context.getString(R.string.ConversationItem_group_action_left, r.getDisplayName(context)), R.drawable.ic_update_group_leave_16);
|
||||
} else if (isIncomingAudioCall()) {
|
||||
return staticUpdateDescription(context.getString(R.string.MessageRecord_call_message_with_date, context.getString(R.string.MessageRecord_incoming_voice_call), getCallDateString(context)), R.drawable.ic_update_audio_call_incoming_16);
|
||||
} else if (isIncomingVideoCall()) {
|
||||
@@ -191,47 +188,47 @@ public abstract class MessageRecord extends DisplayRecord {
|
||||
} else if (isGroupCall()) {
|
||||
return getGroupCallUpdateDescription(context, getBody(), true);
|
||||
} else if (isJoined()) {
|
||||
return staticUpdateDescription(context.getString(R.string.MessageRecord_s_joined_signal, getIndividualRecipient().getDisplayName(context)), R.drawable.ic_update_group_add_16);
|
||||
return staticUpdateDescription(context.getString(R.string.MessageRecord_s_joined_signal, getFromRecipient().getDisplayName(context)), R.drawable.ic_update_group_add_16);
|
||||
} else if (isExpirationTimerUpdate()) {
|
||||
int seconds = (int)(getExpiresIn() / 1000);
|
||||
if (seconds <= 0) {
|
||||
return isOutgoing() ? staticUpdateDescription(context.getString(R.string.MessageRecord_you_disabled_disappearing_messages), R.drawable.ic_update_timer_disabled_16)
|
||||
: fromRecipient(getIndividualRecipient(), r -> context.getString(R.string.MessageRecord_s_disabled_disappearing_messages, r.getDisplayName(context)), R.drawable.ic_update_timer_disabled_16);
|
||||
: fromRecipient(getFromRecipient(), r -> context.getString(R.string.MessageRecord_s_disabled_disappearing_messages, r.getDisplayName(context)), R.drawable.ic_update_timer_disabled_16);
|
||||
}
|
||||
String time = ExpirationUtil.getExpirationDisplayValue(context, seconds);
|
||||
return isOutgoing() ? staticUpdateDescription(context.getString(R.string.MessageRecord_you_set_disappearing_message_time_to_s, time), R.drawable.ic_update_timer_16)
|
||||
: fromRecipient(getIndividualRecipient(), r -> context.getString(R.string.MessageRecord_s_set_disappearing_message_time_to_s, r.getDisplayName(context), time), R.drawable.ic_update_timer_16);
|
||||
: fromRecipient(getFromRecipient(), r -> context.getString(R.string.MessageRecord_s_set_disappearing_message_time_to_s, r.getDisplayName(context), time), R.drawable.ic_update_timer_16);
|
||||
} else if (isIdentityUpdate()) {
|
||||
return fromRecipient(getIndividualRecipient(), r -> context.getString(R.string.MessageRecord_your_safety_number_with_s_has_changed, r.getDisplayName(context)), R.drawable.ic_update_safety_number_16);
|
||||
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 if (isIdentityVerified()) {
|
||||
if (isOutgoing()) return fromRecipient(getIndividualRecipient(), r -> context.getString(R.string.MessageRecord_you_marked_your_safety_number_with_s_verified, r.getDisplayName(context)), R.drawable.ic_update_verified_16);
|
||||
else return fromRecipient(getIndividualRecipient(), r -> context.getString(R.string.MessageRecord_you_marked_your_safety_number_with_s_verified_from_another_device, r.getDisplayName(context)), R.drawable.ic_update_verified_16);
|
||||
if (isOutgoing()) return fromRecipient(getFromRecipient(), r -> context.getString(R.string.MessageRecord_you_marked_your_safety_number_with_s_verified, r.getDisplayName(context)), R.drawable.ic_update_verified_16);
|
||||
else return fromRecipient(getFromRecipient(), r -> context.getString(R.string.MessageRecord_you_marked_your_safety_number_with_s_verified_from_another_device, r.getDisplayName(context)), R.drawable.ic_update_verified_16);
|
||||
} else if (isIdentityDefault()) {
|
||||
if (isOutgoing()) return fromRecipient(getIndividualRecipient(), r -> context.getString(R.string.MessageRecord_you_marked_your_safety_number_with_s_unverified, r.getDisplayName(context)), R.drawable.ic_update_info_16);
|
||||
else return fromRecipient(getIndividualRecipient(), r -> context.getString(R.string.MessageRecord_you_marked_your_safety_number_with_s_unverified_from_another_device, r.getDisplayName(context)), R.drawable.ic_update_info_16);
|
||||
if (isOutgoing()) return fromRecipient(getFromRecipient(), r -> context.getString(R.string.MessageRecord_you_marked_your_safety_number_with_s_unverified, r.getDisplayName(context)), R.drawable.ic_update_info_16);
|
||||
else return fromRecipient(getFromRecipient(), r -> context.getString(R.string.MessageRecord_you_marked_your_safety_number_with_s_unverified_from_another_device, r.getDisplayName(context)), R.drawable.ic_update_info_16);
|
||||
} else if (isProfileChange()) {
|
||||
return staticUpdateDescription(getProfileChangeDescription(context), R.drawable.ic_update_profile_16);
|
||||
} else if (isChangeNumber()) {
|
||||
return fromRecipient(getIndividualRecipient(), r -> context.getString(R.string.MessageRecord_s_changed_their_phone_number, r.getDisplayName(context)), R.drawable.ic_phone_16);
|
||||
return fromRecipient(getFromRecipient(), r -> context.getString(R.string.MessageRecord_s_changed_their_phone_number, r.getDisplayName(context)), R.drawable.ic_phone_16);
|
||||
} else if (isBoostRequest()) {
|
||||
return staticUpdateDescription(context.getString(R.string.MessageRecord_like_this_new_feature_help_support_signal_with_a_one_time_donation), 0);
|
||||
} else if (isEndSession()) {
|
||||
if (isOutgoing()) return staticUpdateDescription(context.getString(R.string.SmsMessageRecord_secure_session_reset), R.drawable.ic_update_info_16);
|
||||
else return fromRecipient(getIndividualRecipient(), r-> context.getString(R.string.SmsMessageRecord_secure_session_reset_s, r.getDisplayName(context)), R.drawable.ic_update_info_16);
|
||||
else return fromRecipient(getFromRecipient(), r-> context.getString(R.string.SmsMessageRecord_secure_session_reset_s, r.getDisplayName(context)), R.drawable.ic_update_info_16);
|
||||
} else if (isGroupV1MigrationEvent()) {
|
||||
return getGroupMigrationEventDescription(context);
|
||||
} else if (isChatSessionRefresh()) {
|
||||
return staticUpdateDescription(context.getString(R.string.MessageRecord_chat_session_refreshed), R.drawable.ic_refresh_16);
|
||||
} else if (isBadDecryptType()) {
|
||||
return fromRecipient(getIndividualRecipient(), r -> context.getString(R.string.MessageRecord_a_message_from_s_couldnt_be_delivered, r.getDisplayName(context)), R.drawable.ic_error_outline_14);
|
||||
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()));
|
||||
|
||||
if (event.getPreviousE164().isEmpty()) {
|
||||
return fromRecipient(getIndividualRecipient(), 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);
|
||||
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(getIndividualRecipient(), 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.getPreviousE164())), R.drawable.ic_thread_merge_16);
|
||||
}
|
||||
} catch (InvalidProtocolBufferException e) {
|
||||
throw new AssertionError(e);
|
||||
@@ -241,9 +238,9 @@ public abstract class MessageRecord extends DisplayRecord {
|
||||
SessionSwitchoverEvent event = SessionSwitchoverEvent.parseFrom(Base64.decodeOrThrow(getBody()));
|
||||
|
||||
if (event.getE164().isEmpty()) {
|
||||
return fromRecipient(getIndividualRecipient(), r -> context.getString(R.string.MessageRecord_your_safety_number_with_s_has_changed, r.getDisplayName(context)), R.drawable.ic_update_safety_number_16);
|
||||
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(getIndividualRecipient(), r -> context.getString(R.string.MessageRecord_s_belongs_to_s, PhoneNumberFormatter.prettyPrint(r.requireE164()), r.getDisplayName(context)), R.drawable.ic_update_info_16);
|
||||
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) {
|
||||
throw new AssertionError(e);
|
||||
@@ -251,13 +248,13 @@ public abstract class MessageRecord extends DisplayRecord {
|
||||
} else if (isSmsExportType()) {
|
||||
int messageResource = SignalStore.misc().getSmsExportPhase().isSmsSupported() ? R.string.MessageRecord__you_will_no_longer_be_able_to_send_sms_messages_from_signal_soon
|
||||
: R.string.MessageRecord__you_can_no_longer_send_sms_messages_in_signal;
|
||||
return fromRecipient(getIndividualRecipient(), r -> context.getString(messageResource, r.getDisplayName(context)), R.drawable.ic_update_info_16);
|
||||
return fromRecipient(getFromRecipient(), r -> context.getString(messageResource, r.getDisplayName(context)), R.drawable.ic_update_info_16);
|
||||
} else if (isPaymentsRequestToActivate()) {
|
||||
return isOutgoing() ? fromRecipient(getIndividualRecipient(), r -> context.getString(R.string.MessageRecord_you_sent_request, r.getShortDisplayName(context)), R.drawable.ic_card_activate_payments)
|
||||
: fromRecipient(getIndividualRecipient(), r -> context.getString(R.string.MessageRecord_wants_you_to_activate_payments, r.getShortDisplayName(context)), R.drawable.ic_card_activate_payments);
|
||||
return isOutgoing() ? fromRecipient(getFromRecipient(), r -> context.getString(R.string.MessageRecord_you_sent_request, r.getShortDisplayName(context)), R.drawable.ic_card_activate_payments)
|
||||
: fromRecipient(getFromRecipient(), r -> context.getString(R.string.MessageRecord_wants_you_to_activate_payments, r.getShortDisplayName(context)), R.drawable.ic_card_activate_payments);
|
||||
} else if (isPaymentsActivated()) {
|
||||
return isOutgoing() ? staticUpdateDescription(context.getString(R.string.MessageRecord_you_activated_payments), R.drawable.ic_card_activate_payments)
|
||||
: fromRecipient(getIndividualRecipient(), r -> context.getString(R.string.MessageRecord_can_accept_payments, r.getShortDisplayName(context)), R.drawable.ic_card_activate_payments);
|
||||
: fromRecipient(getFromRecipient(), r -> context.getString(R.string.MessageRecord_can_accept_payments, r.getShortDisplayName(context)), R.drawable.ic_card_activate_payments);
|
||||
}
|
||||
|
||||
return null;
|
||||
@@ -383,11 +380,11 @@ public abstract class MessageRecord extends DisplayRecord {
|
||||
ProfileChangeDetails profileChangeDetails = ProfileChangeDetails.parseFrom(decoded);
|
||||
|
||||
if (profileChangeDetails.hasProfileNameChange()) {
|
||||
String displayName = getIndividualRecipient().getDisplayName(context);
|
||||
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());
|
||||
|
||||
if (getIndividualRecipient().isSystemContact()) {
|
||||
if (getFromRecipient().isSystemContact()) {
|
||||
return context.getString(R.string.MessageRecord_changed_their_profile_name_from_to, displayName, previousName, newName);
|
||||
} else {
|
||||
return context.getString(R.string.MessageRecord_changed_their_profile_name_to, previousName, newName);
|
||||
@@ -397,7 +394,7 @@ public abstract class MessageRecord extends DisplayRecord {
|
||||
Log.w(TAG, "Profile name change details could not be read", e);
|
||||
}
|
||||
|
||||
return context.getString(R.string.MessageRecord_changed_their_profile, getIndividualRecipient().getDisplayName(context));
|
||||
return context.getString(R.string.MessageRecord_changed_their_profile, getFromRecipient().getDisplayName(context));
|
||||
}
|
||||
|
||||
private UpdateDescription getGroupMigrationEventDescription(@NonNull Context context) {
|
||||
@@ -600,12 +597,8 @@ public abstract class MessageRecord extends DisplayRecord {
|
||||
return false;
|
||||
}
|
||||
|
||||
public Recipient getIndividualRecipient() {
|
||||
return individualRecipient.live().get();
|
||||
}
|
||||
|
||||
public int getRecipientDeviceId() {
|
||||
return recipientDeviceId;
|
||||
public int getFromDeviceId() {
|
||||
return authorDeviceId;
|
||||
}
|
||||
|
||||
public long getType() {
|
||||
@@ -625,7 +618,7 @@ public abstract class MessageRecord extends DisplayRecord {
|
||||
}
|
||||
|
||||
public boolean hasFailedWithNetworkFailures() {
|
||||
return isFailed() && ((getRecipient().isPushGroup() && hasNetworkFailures()) || !isIdentityMismatchFailure());
|
||||
return isFailed() && ((getToRecipient().isPushGroup() && hasNetworkFailures()) || !isIdentityMismatchFailure());
|
||||
}
|
||||
|
||||
public boolean isChatSessionRefresh() {
|
||||
|
||||
@@ -29,8 +29,7 @@ public abstract class MmsMessageRecord extends MessageRecord {
|
||||
|
||||
private final boolean viewOnce;
|
||||
|
||||
MmsMessageRecord(long id, String body, Recipient conversationRecipient,
|
||||
Recipient individualRecipient, int recipientDeviceId, long dateSent,
|
||||
MmsMessageRecord(long id, String body, Recipient fromRecipient, int fromDeviceId, Recipient toRecipient, long dateSent,
|
||||
long dateReceived, long dateServer, long threadId, int deliveryStatus, int deliveryReceiptCount,
|
||||
long type, Set<IdentityKeyMismatch> mismatches,
|
||||
Set<NetworkFailure> networkFailures, int subscriptionId, long expiresIn,
|
||||
@@ -42,7 +41,7 @@ public abstract class MmsMessageRecord extends MessageRecord {
|
||||
int viewedReceiptCount, long receiptTimestamp, @NonNull StoryType storyType,
|
||||
@Nullable ParentStoryId parentStoryId, @Nullable GiftBadge giftBadge)
|
||||
{
|
||||
super(id, body, conversationRecipient, individualRecipient, recipientDeviceId,
|
||||
super(id, body, fromRecipient, fromDeviceId, toRecipient,
|
||||
dateSent, dateReceived, dateServer, threadId, deliveryStatus, deliveryReceiptCount,
|
||||
type, mismatches, networkFailures, subscriptionId, expiresIn, expireStarted, readReceiptCount,
|
||||
unidentified, reactions, remoteDelete, notifiedTimestamp, viewedReceiptCount, receiptTimestamp);
|
||||
|
||||
@@ -48,8 +48,7 @@ public class NotificationMmsMessageRecord extends MmsMessageRecord {
|
||||
private final int status;
|
||||
private final byte[] transactionId;
|
||||
|
||||
public NotificationMmsMessageRecord(long id, Recipient conversationRecipient,
|
||||
Recipient individualRecipient, int recipientDeviceId,
|
||||
public NotificationMmsMessageRecord(long id, Recipient fromRecipient, int fromDeviceId, Recipient toRecipient,
|
||||
long dateSent, long dateReceived, int deliveryReceiptCount,
|
||||
long threadId, byte[] contentLocation, long messageSize,
|
||||
long expiry, int status, byte[] transactionId, long mailbox,
|
||||
@@ -57,7 +56,7 @@ public class NotificationMmsMessageRecord extends MmsMessageRecord {
|
||||
int viewedReceiptCount, long receiptTimestamp, @NonNull StoryType storyType,
|
||||
@Nullable ParentStoryId parentStoryId, @Nullable GiftBadge giftBadge)
|
||||
{
|
||||
super(id, "", conversationRecipient, individualRecipient, recipientDeviceId,
|
||||
super(id, "", fromRecipient, fromDeviceId, toRecipient,
|
||||
dateSent, dateReceived, -1, threadId, Status.STATUS_NONE, deliveryReceiptCount, mailbox,
|
||||
new HashSet<>(), new HashSet<>(), subscriptionId,
|
||||
0, 0, false, slideDeck, readReceiptCount, null, Collections.emptyList(), Collections.emptyList(), false,
|
||||
|
||||
Reference in New Issue
Block a user