Add urgency flag to message sends.

This commit is contained in:
Cody Henthorne
2022-08-01 13:06:51 -04:00
committed by Greyson Parrelli
parent c7cd261641
commit dc04c8ed98
38 changed files with 256 additions and 139 deletions

View File

@@ -6,6 +6,8 @@ import net.zetetic.database.sqlcipher.SQLiteConstraintException
import org.signal.core.util.CursorUtil
import org.signal.core.util.SqlUtil
import org.signal.core.util.logging.Log
import org.signal.core.util.requireBoolean
import org.signal.core.util.toInt
import org.thoughtcrime.securesms.database.model.MessageId
import org.thoughtcrime.securesms.database.model.MessageLogEntry
import org.thoughtcrime.securesms.recipients.Recipient
@@ -67,13 +69,15 @@ class MessageSendLogDatabase constructor(context: Context?, databaseHelper: Sign
const val DATE_SENT = "date_sent"
const val CONTENT = "content"
const val CONTENT_HINT = "content_hint"
const val URGENT = "urgent"
const val CREATE_TABLE = """
CREATE TABLE $TABLE_NAME (
$ID INTEGER PRIMARY KEY,
$DATE_SENT INTEGER NOT NULL,
$CONTENT BLOB NOT NULL,
$CONTENT_HINT INTEGER NOT NULL
$CONTENT_HINT INTEGER NOT NULL,
$URGENT INTEGER NOT NULL DEFAULT 1
)
"""
@@ -152,31 +156,31 @@ class MessageSendLogDatabase constructor(context: Context?, databaseHelper: Sign
}
/** @return The ID of the inserted entry, or -1 if none was inserted. Can be used with [addRecipientToExistingEntryIfPossible] */
fun insertIfPossible(recipientId: RecipientId, sentTimestamp: Long, sendMessageResult: SendMessageResult, contentHint: ContentHint, messageId: MessageId): Long {
fun insertIfPossible(recipientId: RecipientId, sentTimestamp: Long, sendMessageResult: SendMessageResult, contentHint: ContentHint, messageId: MessageId, urgent: Boolean): Long {
if (!FeatureFlags.retryReceipts()) return -1
if (sendMessageResult.isSuccess && sendMessageResult.success.content.isPresent) {
val recipientDevice = listOf(RecipientDevice(recipientId, sendMessageResult.success.devices))
return insert(recipientDevice, sentTimestamp, sendMessageResult.success.content.get(), contentHint, listOf(messageId))
return insert(recipientDevice, sentTimestamp, sendMessageResult.success.content.get(), contentHint, listOf(messageId), urgent)
}
return -1
}
/** @return The ID of the inserted entry, or -1 if none was inserted. Can be used with [addRecipientToExistingEntryIfPossible] */
fun insertIfPossible(recipientId: RecipientId, sentTimestamp: Long, sendMessageResult: SendMessageResult, contentHint: ContentHint, messageIds: List<MessageId>): Long {
fun insertIfPossible(recipientId: RecipientId, sentTimestamp: Long, sendMessageResult: SendMessageResult, contentHint: ContentHint, messageIds: List<MessageId>, urgent: Boolean): Long {
if (!FeatureFlags.retryReceipts()) return -1
if (sendMessageResult.isSuccess && sendMessageResult.success.content.isPresent) {
val recipientDevice = listOf(RecipientDevice(recipientId, sendMessageResult.success.devices))
return insert(recipientDevice, sentTimestamp, sendMessageResult.success.content.get(), contentHint, messageIds)
return insert(recipientDevice, sentTimestamp, sendMessageResult.success.content.get(), contentHint, messageIds, urgent)
}
return -1
}
/** @return The ID of the inserted entry, or -1 if none was inserted. Can be used with [addRecipientToExistingEntryIfPossible] */
fun insertIfPossible(sentTimestamp: Long, possibleRecipients: List<Recipient>, results: List<SendMessageResult>, contentHint: ContentHint, messageId: MessageId): Long {
fun insertIfPossible(sentTimestamp: Long, possibleRecipients: List<Recipient>, results: List<SendMessageResult>, contentHint: ContentHint, messageId: MessageId, urgent: Boolean): Long {
if (!FeatureFlags.retryReceipts()) return -1
val accessList = RecipientAccessList(possibleRecipients)
@@ -194,10 +198,10 @@ class MessageSendLogDatabase constructor(context: Context?, databaseHelper: Sign
val content: SignalServiceProtos.Content = results.first { it.isSuccess && it.success.content.isPresent }.success.content.get()
return insert(recipientDevices, sentTimestamp, content, contentHint, listOf(messageId))
return insert(recipientDevices, sentTimestamp, content, contentHint, listOf(messageId), urgent)
}
fun addRecipientToExistingEntryIfPossible(payloadId: Long, recipientId: RecipientId, sentTimestamp: Long, sendMessageResult: SendMessageResult, contentHint: ContentHint, messageId: MessageId): Long {
fun addRecipientToExistingEntryIfPossible(payloadId: Long, recipientId: RecipientId, sentTimestamp: Long, sendMessageResult: SendMessageResult, contentHint: ContentHint, messageId: MessageId, urgent: Boolean): Long {
if (!FeatureFlags.retryReceipts()) return payloadId
if (sendMessageResult.isSuccess && sendMessageResult.success.content.isPresent) {
@@ -218,9 +222,9 @@ class MessageSendLogDatabase constructor(context: Context?, databaseHelper: Sign
db.setTransactionSuccessful()
} catch (e: SQLiteConstraintException) {
Log.w(TAG, "Failed to append to existing entry. Creating a new one.")
val payloadId = insertIfPossible(recipientId, sentTimestamp, sendMessageResult, contentHint, messageId)
val newPayloadId = insertIfPossible(recipientId, sentTimestamp, sendMessageResult, contentHint, messageId, urgent)
db.setTransactionSuccessful()
return payloadId
return newPayloadId
} finally {
db.endTransaction()
}
@@ -229,7 +233,7 @@ class MessageSendLogDatabase constructor(context: Context?, databaseHelper: Sign
return payloadId
}
private fun insert(recipients: List<RecipientDevice>, dateSent: Long, content: SignalServiceProtos.Content, contentHint: ContentHint, messageIds: List<MessageId>): Long {
private fun insert(recipients: List<RecipientDevice>, dateSent: Long, content: SignalServiceProtos.Content, contentHint: ContentHint, messageIds: List<MessageId>, urgent: Boolean): Long {
val db = databaseHelper.signalWritableDatabase
db.beginTransaction()
@@ -238,6 +242,7 @@ class MessageSendLogDatabase constructor(context: Context?, databaseHelper: Sign
put(PayloadTable.DATE_SENT, dateSent)
put(PayloadTable.CONTENT, content.toByteArray())
put(PayloadTable.CONTENT_HINT, contentHint.type)
put(PayloadTable.URGENT, urgent.toInt())
}
val payloadId: Long = db.insert(PayloadTable.TABLE_NAME, null, payloadValues)
@@ -304,6 +309,7 @@ class MessageSendLogDatabase constructor(context: Context?, databaseHelper: Sign
dateSent = CursorUtil.requireLong(entryCursor, PayloadTable.DATE_SENT),
content = SignalServiceProtos.Content.parseFrom(CursorUtil.requireBlob(entryCursor, PayloadTable.CONTENT)),
contentHint = ContentHint.fromType(CursorUtil.requireInt(entryCursor, PayloadTable.CONTENT_HINT)),
urgent = entryCursor.requireBoolean(PayloadTable.URGENT),
relatedMessages = messageIds
)
}

View File

@@ -94,7 +94,8 @@ public class PushDatabase extends Database {
cursor.getLong(cursor.getColumnIndexOrThrow(SERVER_RECEIVED_TIMESTAMP)),
cursor.getLong(cursor.getColumnIndexOrThrow(SERVER_DELIVERED_TIMESTAMP)),
cursor.getString(cursor.getColumnIndexOrThrow(SERVER_GUID)),
"");
"",
true);
}
} catch (IOException e) {
Log.w(TAG, e);
@@ -180,7 +181,8 @@ public class PushDatabase extends Database {
serverReceivedTimestamp,
serverDeliveredTimestamp,
serverGuid,
"");
"",
true);
} catch (IOException e) {
throw new AssertionError(e);
}

View File

@@ -26,6 +26,7 @@ import org.thoughtcrime.securesms.conversation.colors.ChatColors
import org.thoughtcrime.securesms.conversation.colors.ChatColorsMapper.entrySet
import org.thoughtcrime.securesms.database.KeyValueDatabase
import org.thoughtcrime.securesms.database.RecipientDatabase
import org.thoughtcrime.securesms.database.helpers.migration.UrgentMslFlagMigration
import org.thoughtcrime.securesms.database.model.databaseprotos.ReactionList
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies
import org.thoughtcrime.securesms.groups.GroupId
@@ -203,8 +204,9 @@ object SignalDatabaseMigrations {
private const val QUOTE_INDEX = 147
private const val MY_STORY_PRIVACY_MODE = 148
private const val EXPIRING_PROFILE_CREDENTIALS = 149
private const val URGENT_FLAG = 150
const val DATABASE_VERSION = 149
const val DATABASE_VERSION = 150
@JvmStatic
fun migrate(context: Application, db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
@@ -2663,6 +2665,10 @@ object SignalDatabaseMigrations {
if (oldVersion < EXPIRING_PROFILE_CREDENTIALS) {
db.execSQL("UPDATE recipient SET profile_key_credential = NULL")
}
if (oldVersion < URGENT_FLAG) {
UrgentMslFlagMigration.migrate(context, db, oldVersion, newVersion)
}
}
@JvmStatic

View File

@@ -0,0 +1,11 @@
package org.thoughtcrime.securesms.database.helpers.migration
import android.app.Application
import net.zetetic.database.sqlcipher.SQLiteDatabase
/**
* Simple interface for allowing database migrations to live outside of [org.thoughtcrime.securesms.database.helpers.SignalDatabaseMigrations].
*/
interface SignalDatabaseMigration {
fun migrate(context: Application, db: SQLiteDatabase, oldVersion: Int, newVersion: Int)
}

View File

@@ -0,0 +1,14 @@
package org.thoughtcrime.securesms.database.helpers.migration
import android.app.Application
import net.zetetic.database.sqlcipher.SQLiteDatabase
/**
* Adding an urgent flag to message envelopes to help with notifications. Need to track flag in
* MSL table so can be resent with the correct urgency.
*/
object UrgentMslFlagMigration : SignalDatabaseMigration {
override fun migrate(context: Application, db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
db.execSQL("ALTER TABLE msl_payload ADD COLUMN urgent INTEGER NOT NULL DEFAULT 1")
}
}

View File

@@ -12,6 +12,8 @@ data class MessageLogEntry(
val dateSent: Long,
val content: SignalServiceProtos.Content,
val contentHint: ContentHint,
@get:JvmName("isUrgent")
val urgent: Boolean,
val relatedMessages: List<MessageId>
) {
val hasRelatedMessage: Boolean

View File

@@ -1273,16 +1273,7 @@ final class GroupManagerV2 {
GroupId.V2 groupId = GroupId.v2(masterKey);
Recipient groupRecipient = Recipient.externalGroupExact(groupId);
DecryptedGroupV2Context decryptedGroupV2Context = GroupProtoUtil.createDecryptedGroupV2Context(masterKey, groupMutation, signedGroupChange);
OutgoingGroupUpdateMessage outgoingMessage = new OutgoingGroupUpdateMessage(groupRecipient,
decryptedGroupV2Context,
null,
System.currentTimeMillis(),
0,
false,
null,
Collections.emptyList(),
Collections.emptyList(),
Collections.emptyList());
OutgoingGroupUpdateMessage outgoingMessage = new OutgoingGroupUpdateMessage(groupRecipient, decryptedGroupV2Context, System.currentTimeMillis());
DecryptedGroupChange plainGroupChange = groupMutation.getGroupChange();

View File

@@ -464,18 +464,8 @@ public class GroupsV2StateProcessor {
.addDeleteMembers(UuidUtil.toByteString(selfUuid))
.build();
DecryptedGroupV2Context decryptedGroupV2Context = GroupProtoUtil.createDecryptedGroupV2Context(masterKey, new GroupMutation(decryptedGroup, simulatedGroupChange, simulatedGroupState), null);
OutgoingGroupUpdateMessage leaveMessage = new OutgoingGroupUpdateMessage(groupRecipient,
decryptedGroupV2Context,
null,
System.currentTimeMillis(),
0,
false,
null,
Collections.emptyList(),
Collections.emptyList(),
Collections.emptyList());
DecryptedGroupV2Context decryptedGroupV2Context = GroupProtoUtil.createDecryptedGroupV2Context(masterKey, new GroupMutation(decryptedGroup, simulatedGroupChange, simulatedGroupState), null);
OutgoingGroupUpdateMessage leaveMessage = new OutgoingGroupUpdateMessage(groupRecipient, decryptedGroupV2Context, System.currentTimeMillis());
try {
MessageDatabase mmsDatabase = SignalDatabase.mms();
@@ -703,7 +693,7 @@ public class GroupsV2StateProcessor {
ThreadDatabase threadDatabase = SignalDatabase.threads();
RecipientId recipientId = recipientDatabase.getOrInsertFromGroupId(groupId);
Recipient recipient = Recipient.resolved(recipientId);
OutgoingGroupUpdateMessage outgoingMessage = new OutgoingGroupUpdateMessage(recipient, decryptedGroupV2Context, null, timestamp, 0, false, null, Collections.emptyList(), Collections.emptyList(), Collections.emptyList());
OutgoingGroupUpdateMessage outgoingMessage = new OutgoingGroupUpdateMessage(recipient, decryptedGroupV2Context, timestamp);
long threadId = threadDatabase.getOrCreateThreadIdFor(recipient);
long messageId = mmsDatabase.insertMessageOutbox(outgoingMessage, threadId, false, null);

View File

@@ -57,9 +57,9 @@ public class GroupCallUpdateSendJob extends BaseJob {
}
List<RecipientId> recipientIds = Stream.of(RecipientUtil.getEligibleForSending(Recipient.resolvedList(conversationRecipient.getParticipantIds())))
.filterNot(Recipient::isSelf)
.map(Recipient::getId)
.toList();
.filterNot(Recipient::isSelf)
.map(Recipient::getId)
.toList();
return new GroupCallUpdateSendJob(recipientId,
eraId,
@@ -161,7 +161,8 @@ public class GroupCallUpdateSendJob extends BaseJob {
nonSelfDestinations,
false,
ContentHint.DEFAULT,
dataMessage);
dataMessage,
false);
if (includesSelf) {
results.add(ApplicationDependencies.getSignalServiceMessageSender().sendSyncMessage(dataMessage));

View File

@@ -110,7 +110,7 @@ public final class PaymentNotificationSendJob extends BaseJob {
.withPayment(new SignalServiceDataMessage.Payment(new SignalServiceDataMessage.PaymentNotification(payment.getReceipt(), payment.getNote())))
.build();
SendMessageResult sendMessageResult = messageSender.sendDataMessage(address, unidentifiedAccess, ContentHint.DEFAULT, dataMessage, IndividualSendEvents.EMPTY);
SendMessageResult sendMessageResult = messageSender.sendDataMessage(address, unidentifiedAccess, ContentHint.DEFAULT, dataMessage, IndividualSendEvents.EMPTY, false);
if (sendMessageResult.getIdentityFailure() != null) {
Log.w(TAG, "Identity failure for " + recipient.getId());

View File

@@ -153,7 +153,7 @@ public class ProfileKeySendJob extends BaseJob {
.withTimestamp(System.currentTimeMillis())
.withProfileKey(Recipient.self().resolve().getProfileKey());
List<SendMessageResult> results = GroupSendUtil.sendUnresendableDataMessage(context, null, destinations, false, ContentHint.IMPLICIT, dataMessage.build());
List<SendMessageResult> results = GroupSendUtil.sendUnresendableDataMessage(context, null, destinations, false, ContentHint.IMPLICIT, dataMessage.build(), false);
return GroupSendJobHelper.getCompletedSends(destinations, results).completed;
}

View File

@@ -292,7 +292,7 @@ public final class PushGroupSendJob extends PushSendJob {
.withExpiration(groupRecipient.getExpiresInSeconds())
.asGroupMessage(group)
.build();
return GroupSendUtil.sendResendableDataMessage(context, groupRecipient.requireGroupId().requireV2(), destinations, isRecipientUpdate, ContentHint.IMPLICIT, new MessageId(messageId, true), groupDataMessage);
return GroupSendUtil.sendResendableDataMessage(context, groupRecipient.requireGroupId().requireV2(), destinations, isRecipientUpdate, ContentHint.IMPLICIT, new MessageId(messageId, true), groupDataMessage, message.isUrgent());
} else {
throw new UndeliverableMessageException("Messages can no longer be sent to V1 groups!");
}
@@ -351,7 +351,8 @@ public final class PushGroupSendJob extends PushSendJob {
isRecipientUpdate,
ContentHint.RESENDABLE,
new MessageId(messageId, true),
groupMessageBuilder.build());
groupMessageBuilder.build(),
message.isUrgent());
}
} catch (ServerRejectedException e) {
throw new UndeliverableMessageException(e);

View File

@@ -175,7 +175,7 @@ public final class PushGroupSilentUpdateSendJob extends BaseJob {
.asGroupMessage(group)
.build();
List<SendMessageResult> results = GroupSendUtil.sendUnresendableDataMessage(context, groupId, destinations, false, ContentHint.IMPLICIT, groupDataMessage);
List<SendMessageResult> results = GroupSendUtil.sendUnresendableDataMessage(context, groupId, destinations, false, ContentHint.IMPLICIT, groupDataMessage, false);
return GroupSendJobHelper.getCompletedSends(destinations, results).completed;
}

View File

@@ -254,11 +254,11 @@ public class PushMediaSendJob extends PushSendJob {
if (Util.equals(SignalStore.account().getAci(), address.getServiceId())) {
Optional<UnidentifiedAccessPair> syncAccess = UnidentifiedAccessUtil.getAccessForSync(context);
SendMessageResult result = messageSender.sendSyncMessage(mediaMessage);
SignalDatabase.messageLog().insertIfPossible(messageRecipient.getId(), message.getSentTimeMillis(), result, ContentHint.RESENDABLE, new MessageId(messageId, true));
SignalDatabase.messageLog().insertIfPossible(messageRecipient.getId(), message.getSentTimeMillis(), result, ContentHint.RESENDABLE, new MessageId(messageId, true), false);
return syncAccess.isPresent();
} else {
SendMessageResult result = messageSender.sendDataMessage(address, UnidentifiedAccessUtil.getAccessFor(context, messageRecipient), ContentHint.RESENDABLE, mediaMessage, IndividualSendEvents.EMPTY);
SignalDatabase.messageLog().insertIfPossible(messageRecipient.getId(), message.getSentTimeMillis(), result, ContentHint.RESENDABLE, new MessageId(messageId, true));
SendMessageResult result = messageSender.sendDataMessage(address, UnidentifiedAccessUtil.getAccessFor(context, messageRecipient), ContentHint.RESENDABLE, mediaMessage, IndividualSendEvents.EMPTY, message.isUrgent());
SignalDatabase.messageLog().insertIfPossible(messageRecipient.getId(), message.getSentTimeMillis(), result, ContentHint.RESENDABLE, new MessageId(messageId, true), message.isUrgent());
return result.getSuccess().isUnidentified();
}
} catch (UnregisteredUserException e) {

View File

@@ -194,13 +194,13 @@ public class PushTextSendJob extends PushSendJob {
SignalLocalMetrics.IndividualMessageSend.onDeliveryStarted(messageId);
SendMessageResult result = messageSender.sendSyncMessage(textSecureMessage);
SignalDatabase.messageLog().insertIfPossible(messageRecipient.getId(), message.getDateSent(), result, ContentHint.RESENDABLE, new MessageId(messageId, false));
SignalDatabase.messageLog().insertIfPossible(messageRecipient.getId(), message.getDateSent(), result, ContentHint.RESENDABLE, new MessageId(messageId, false), false);
return syncAccess.isPresent();
} else {
SignalLocalMetrics.IndividualMessageSend.onDeliveryStarted(messageId);
SendMessageResult result = messageSender.sendDataMessage(address, unidentifiedAccess, ContentHint.RESENDABLE, textSecureMessage, new MetricEventListener(messageId));
SendMessageResult result = messageSender.sendDataMessage(address, unidentifiedAccess, ContentHint.RESENDABLE, textSecureMessage, new MetricEventListener(messageId), true);
SignalDatabase.messageLog().insertIfPossible(messageRecipient.getId(), message.getDateSent(), result, ContentHint.RESENDABLE, new MessageId(messageId, false));
SignalDatabase.messageLog().insertIfPossible(messageRecipient.getId(), message.getDateSent(), result, ContentHint.RESENDABLE, new MessageId(messageId, false), true);
return result.getSuccess().isUnidentified();
}
} catch (UnregisteredUserException e) {

View File

@@ -242,7 +242,8 @@ public class ReactionSendJob extends BaseJob {
false,
ContentHint.RESENDABLE,
messageId,
dataMessage);
dataMessage,
true);
if (includesSelf) {
results.add(ApplicationDependencies.getSignalServiceMessageSender().sendSyncMessage(dataMessage));

View File

@@ -214,7 +214,8 @@ public class RemoteDeleteSendJob extends BaseJob {
false,
ContentHint.RESENDABLE,
new MessageId(messageId, isMms),
dataMessage);
dataMessage,
true);
return GroupSendJobHelper.getCompletedSends(destinations, results);
}

View File

@@ -51,6 +51,7 @@ public class ResendMessageJob extends BaseJob {
private final long sentTimestamp;
private final Content content;
private final ContentHint contentHint;
private final boolean urgent;
private final GroupId.V2 groupId;
private final DistributionId distributionId;
@@ -58,6 +59,7 @@ public class ResendMessageJob extends BaseJob {
private static final String KEY_SENT_TIMESTAMP = "sent_timestamp";
private static final String KEY_CONTENT = "content";
private static final String KEY_CONTENT_HINT = "content_hint";
private static final String KEY_URGENT = "urgent";
private static final String KEY_GROUP_ID = "group_id";
private static final String KEY_DISTRIBUTION_ID = "distribution_id";
@@ -65,6 +67,7 @@ public class ResendMessageJob extends BaseJob {
long sentTimestamp,
@NonNull Content content,
@NonNull ContentHint contentHint,
boolean urgent,
@Nullable GroupId.V2 groupId,
@Nullable DistributionId distributionId)
{
@@ -72,6 +75,7 @@ public class ResendMessageJob extends BaseJob {
sentTimestamp,
content,
contentHint,
urgent,
groupId,
distributionId,
new Parameters.Builder().setQueue(recipientId.toQueueKey())
@@ -85,6 +89,7 @@ public class ResendMessageJob extends BaseJob {
long sentTimestamp,
@NonNull Content content,
@NonNull ContentHint contentHint,
boolean urgent,
@Nullable GroupId.V2 groupId,
@Nullable DistributionId distributionId,
@NonNull Parameters parameters)
@@ -95,6 +100,7 @@ public class ResendMessageJob extends BaseJob {
this.sentTimestamp = sentTimestamp;
this.content = content;
this.contentHint = contentHint;
this.urgent = urgent;
this.groupId = groupId;
this.distributionId = distributionId;
}
@@ -106,6 +112,7 @@ public class ResendMessageJob extends BaseJob {
.putLong(KEY_SENT_TIMESTAMP, sentTimestamp)
.putBlobAsString(KEY_CONTENT, content.toByteArray())
.putInt(KEY_CONTENT_HINT, contentHint.getType())
.putBoolean(KEY_URGENT, urgent)
.putBlobAsString(KEY_GROUP_ID, groupId != null ? groupId.getDecodedId() : null)
.putString(KEY_DISTRIBUTION_ID, distributionId != null ? distributionId.toString() : null)
.build();
@@ -152,7 +159,7 @@ public class ResendMessageJob extends BaseJob {
contentToSend = contentToSend.toBuilder().setSenderKeyDistributionMessage(distributionBytes).build();
}
SendMessageResult result = messageSender.resendContent(address, access, sentTimestamp, contentToSend, contentHint, Optional.ofNullable(groupId).map(GroupId::getDecodedId));
SendMessageResult result = messageSender.resendContent(address, access, sentTimestamp, contentToSend, contentHint, Optional.ofNullable(groupId).map(GroupId::getDecodedId), urgent);
if (result.isSuccess() && distributionId != null) {
List<SignalProtocolAddress> addresses = result.getSuccess()
@@ -195,6 +202,7 @@ public class ResendMessageJob extends BaseJob {
data.getLong(KEY_SENT_TIMESTAMP),
content,
ContentHint.fromType(data.getInt(KEY_CONTENT_HINT)),
data.getBooleanOrDefault(KEY_URGENT, true),
groupId,
distributionId,
parameters);

View File

@@ -122,7 +122,7 @@ public class SendDeliveryReceiptJob extends BaseJob {
receiptMessage);
if (messageId != null) {
SignalDatabase.messageLog().insertIfPossible(recipientId, timestamp, result, ContentHint.IMPLICIT, messageId);
SignalDatabase.messageLog().insertIfPossible(recipientId, timestamp, result, ContentHint.IMPLICIT, messageId, false);
}
}

View File

@@ -186,7 +186,7 @@ public class SendReadReceiptJob extends BaseJob {
receiptMessage);
if (Util.hasItems(messageIds)) {
SignalDatabase.messageLog().insertIfPossible(recipientId, timestamp, result, ContentHint.IMPLICIT, messageIds);
SignalDatabase.messageLog().insertIfPossible(recipientId, timestamp, result, ContentHint.IMPLICIT, messageIds, false);
}
}

View File

@@ -182,7 +182,7 @@ public class SendViewedReceiptJob extends BaseJob {
receiptMessage);
if (Util.hasItems(messageIds)) {
SignalDatabase.messageLog().insertIfPossible(recipientId, timestamp, result, ContentHint.IMPLICIT, messageIds);
SignalDatabase.messageLog().insertIfPossible(recipientId, timestamp, result, ContentHint.IMPLICIT, messageIds, false);
}
}

View File

@@ -101,7 +101,7 @@ public final class SenderKeyDistributionSendJob extends BaseJob {
SenderKeyDistributionMessage message = messageSender.getOrCreateNewGroupSession(distributionId);
List<Optional<UnidentifiedAccessPair>> access = UnidentifiedAccessUtil.getAccessFor(context, Collections.singletonList(recipient));
SendMessageResult result = messageSender.sendSenderKeyDistributionMessage(distributionId, address, access, message, Optional.of(groupId.getDecodedId())).get(0);
SendMessageResult result = messageSender.sendSenderKeyDistributionMessage(distributionId, address, access, message, Optional.of(groupId.getDecodedId()), false).get(0);
if (result.isSuccess()) {
List<SignalProtocolAddress> addresses = result.getSuccess()

View File

@@ -88,10 +88,11 @@ public final class GroupSendUtil {
boolean isRecipientUpdate,
ContentHint contentHint,
@NonNull MessageId messageId,
@NonNull SignalServiceDataMessage message)
@NonNull SignalServiceDataMessage message,
boolean urgent)
throws IOException, UntrustedIdentityException
{
return sendMessage(context, groupId, getDistributionId(groupId), messageId, allTargets, isRecipientUpdate, DataSendOperation.resendable(message, contentHint, messageId), null);
return sendMessage(context, groupId, getDistributionId(groupId), messageId, allTargets, isRecipientUpdate, DataSendOperation.resendable(message, contentHint, messageId, urgent), null);
}
/**
@@ -109,10 +110,11 @@ public final class GroupSendUtil {
@NonNull List<Recipient> allTargets,
boolean isRecipientUpdate,
ContentHint contentHint,
@NonNull SignalServiceDataMessage message)
@NonNull SignalServiceDataMessage message,
boolean urgent)
throws IOException, UntrustedIdentityException
{
return sendMessage(context, groupId, getDistributionId(groupId), null, allTargets, isRecipientUpdate, DataSendOperation.unresendable(message, contentHint), null);
return sendMessage(context, groupId, getDistributionId(groupId), null, allTargets, isRecipientUpdate, DataSendOperation.unresendable(message, contentHint, urgent), null);
}
/**
@@ -295,7 +297,7 @@ public final class GroupSendUtil {
Log.d(TAG, "Successfully sent using sender key to " + successCount + "/" + targets.size() + " sender key targets.");
if (sendOperation.shouldIncludeInMessageLog()) {
SignalDatabase.messageLog().insertIfPossible(sendOperation.getSentTimestamp(), senderKeyTargets, results, sendOperation.getContentHint(), sendOperation.getRelatedMessageId());
SignalDatabase.messageLog().insertIfPossible(sendOperation.getSentTimestamp(), senderKeyTargets, results, sendOperation.getContentHint(), sendOperation.getRelatedMessageId(), sendOperation.isUrgent());
}
if (relatedMessageId != null) {
@@ -353,9 +355,9 @@ public final class GroupSendUtil {
synchronized (entryId) {
if (entryId.get() == -1) {
entryId.set(messageLogDatabase.insertIfPossible(recipients.requireRecipientId(result.getAddress()), sendOperation.getSentTimestamp(), result, sendOperation.getContentHint(), sendOperation.getRelatedMessageId()));
entryId.set(messageLogDatabase.insertIfPossible(recipients.requireRecipientId(result.getAddress()), sendOperation.getSentTimestamp(), result, sendOperation.getContentHint(), sendOperation.getRelatedMessageId(), sendOperation.isUrgent()));
} else {
entryId.set(messageLogDatabase.addRecipientToExistingEntryIfPossible(entryId.get(), recipients.requireRecipientId(result.getAddress()), sendOperation.getSentTimestamp(), result, sendOperation.getContentHint(), sendOperation.getRelatedMessageId()));
entryId.set(messageLogDatabase.addRecipientToExistingEntryIfPossible(entryId.get(), recipients.requireRecipientId(result.getAddress()), sendOperation.getSentTimestamp(), result, sendOperation.getContentHint(), sendOperation.getRelatedMessageId(), sendOperation.isUrgent()));
}
}
}, cancelationSignal);
@@ -424,6 +426,7 @@ public final class GroupSendUtil {
long getSentTimestamp();
boolean shouldIncludeInMessageLog();
@NonNull MessageId getRelatedMessageId();
boolean isUrgent();
}
private static class DataSendOperation implements SendOperation {
@@ -431,20 +434,22 @@ public final class GroupSendUtil {
private final ContentHint contentHint;
private final MessageId relatedMessageId;
private final boolean resendable;
private final boolean urgent;
public static DataSendOperation resendable(@NonNull SignalServiceDataMessage message, @NonNull ContentHint contentHint, @NonNull MessageId relatedMessageId) {
return new DataSendOperation(message, contentHint, true, relatedMessageId);
public static DataSendOperation resendable(@NonNull SignalServiceDataMessage message, @NonNull ContentHint contentHint, @NonNull MessageId relatedMessageId, boolean urgent) {
return new DataSendOperation(message, contentHint, true, relatedMessageId, urgent);
}
public static DataSendOperation unresendable(@NonNull SignalServiceDataMessage message, @NonNull ContentHint contentHint) {
return new DataSendOperation(message, contentHint, false, null);
public static DataSendOperation unresendable(@NonNull SignalServiceDataMessage message, @NonNull ContentHint contentHint, boolean urgent) {
return new DataSendOperation(message, contentHint, false, null, urgent);
}
private DataSendOperation(@NonNull SignalServiceDataMessage message, @NonNull ContentHint contentHint, boolean resendable, @Nullable MessageId relatedMessageId) {
this.message = message;
this.contentHint = contentHint;
this.resendable = resendable;
this.relatedMessageId = relatedMessageId;
private DataSendOperation(@NonNull SignalServiceDataMessage message, @NonNull ContentHint contentHint, boolean resendable, @Nullable MessageId relatedMessageId, boolean urgent) {
this.message = message;
this.contentHint = contentHint;
this.resendable = resendable;
this.relatedMessageId = relatedMessageId;
this.urgent = urgent;
if (resendable && relatedMessageId == null) {
throw new IllegalArgumentException("If a message is resendable, it must have a related message ID!");
@@ -460,7 +465,7 @@ public final class GroupSendUtil {
throws NoSessionException, UntrustedIdentityException, InvalidKeyException, IOException, InvalidRegistrationIdException
{
SenderKeyGroupEvents listener = relatedMessageId != null ? new SenderKeyMetricEventListener(relatedMessageId.getId()) : SenderKeyGroupEvents.EMPTY;
return messageSender.sendGroupDataMessage(distributionId, targets, access, isRecipientUpdate, contentHint, message, listener);
return messageSender.sendGroupDataMessage(distributionId, targets, access, isRecipientUpdate, contentHint, message, listener, urgent);
}
@Override
@@ -473,7 +478,7 @@ public final class GroupSendUtil {
throws IOException, UntrustedIdentityException
{
LegacyGroupEvents listener = relatedMessageId != null ? new LegacyMetricEventListener(relatedMessageId.getId()) : LegacyGroupEvents.EMPTY;
return messageSender.sendDataMessage(targets, access, isRecipientUpdate, contentHint, message, listener, partialListener, cancelationSignal);
return messageSender.sendDataMessage(targets, access, isRecipientUpdate, contentHint, message, listener, partialListener, cancelationSignal, urgent);
}
@Override
@@ -499,6 +504,11 @@ public final class GroupSendUtil {
throw new UnsupportedOperationException();
}
}
@Override
public boolean isUrgent() {
return urgent;
}
}
private static class TypingSendOperation implements SendOperation {
@@ -553,6 +563,11 @@ public final class GroupSendUtil {
public @NonNull MessageId getRelatedMessageId() {
throw new UnsupportedOperationException();
}
@Override
public boolean isUrgent() {
return false;
}
}
private static class CallSendOperation implements SendOperation {
@@ -605,6 +620,11 @@ public final class GroupSendUtil {
public @NonNull MessageId getRelatedMessageId() {
throw new UnsupportedOperationException();
}
@Override
public boolean isUrgent() {
return message.isUrgent();
}
}
public static class StorySendOperation implements SendOperation {
@@ -670,6 +690,11 @@ public final class GroupSendUtil {
public @NonNull MessageId getRelatedMessageId() {
return relatedMessageId;
}
@Override
public boolean isUrgent() {
return false;
}
}
private static final class SenderKeyMetricEventListener implements SenderKeyGroupEvents {

View File

@@ -2694,6 +2694,7 @@ public final class MessageContentProcessor {
messageLogEntry.getDateSent(),
messageLogEntry.getContent(),
messageLogEntry.getContentHint(),
messageLogEntry.isUrgent(),
groupId,
distributionId));
} else {
@@ -2735,6 +2736,7 @@ public final class MessageContentProcessor {
messageLogEntry.getDateSent(),
messageLogEntry.getContent(),
messageLogEntry.getContentHint(),
messageLogEntry.isUrgent(),
null,
null));
} else if (archivedSession) {

View File

@@ -32,4 +32,8 @@ public class OutgoingExpirationUpdateMessage extends OutgoingSecureMediaMessage
return true;
}
@Override
public boolean isUrgent() {
return false;
}
}

View File

@@ -67,16 +67,9 @@ public final class OutgoingGroupUpdateMessage extends OutgoingSecureMediaMessage
public OutgoingGroupUpdateMessage(@NonNull Recipient recipient,
@NonNull DecryptedGroupV2Context group,
@Nullable final Attachment avatar,
long sentTimeMillis,
long expireIn,
boolean viewOnce,
@Nullable QuoteModel quote,
@NonNull List<Contact> contacts,
@NonNull List<LinkPreview> previews,
@NonNull List<Mention> mentions)
long sentTimeMillis)
{
this(recipient, new MessageGroupContext(group), getAttachments(avatar), sentTimeMillis, expireIn, viewOnce, quote, contacts, previews, mentions);
this(recipient, new MessageGroupContext(group), Collections.emptyList(), sentTimeMillis, 0, false, null, Collections.emptyList(), Collections.emptyList(), Collections.emptyList());
}
@Override
@@ -100,6 +93,11 @@ public final class OutgoingGroupUpdateMessage extends OutgoingSecureMediaMessage
return messageGroupContext.requireGroupV2Properties();
}
@Override
public boolean isUrgent() {
return false;
}
private static List<Attachment> getAttachments(@Nullable Attachment avatar) {
return avatar == null ? Collections.emptyList() : Collections.singletonList(avatar);
}

View File

@@ -249,6 +249,10 @@ public class OutgoingMediaMessage {
return giftBadge;
}
public boolean isUrgent() {
return true;
}
private static String buildMessage(SlideDeck slideDeck, String message) {
if (!TextUtils.isEmpty(message) && !TextUtils.isEmpty(slideDeck.getBody())) {
return slideDeck.getBody() + "\n\n" + message;