Separate thread updates into a job and other perf improvements.
This commit is contained in:
parent
db7272730e
commit
665d9e31f6
19 changed files with 268 additions and 110 deletions
|
@ -36,6 +36,9 @@ import org.thoughtcrime.securesms.migrations.LegacyMigrationJob;
|
|||
import org.thoughtcrime.securesms.util.SqlUtil;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
|
||||
public class DatabaseFactory {
|
||||
|
||||
private static final Object lock = new Object();
|
||||
|
@ -311,4 +314,17 @@ public class DatabaseFactory {
|
|||
public boolean hasTable(String table) {
|
||||
return SqlUtil.tableExists(databaseHelper.getRawReadableDatabase(), table);
|
||||
}
|
||||
|
||||
public @NonNull Transaction transaction() {
|
||||
getRawDatabase().beginTransaction();
|
||||
return () -> {
|
||||
getRawDatabase().setTransactionSuccessful();
|
||||
getRawDatabase().endTransaction();
|
||||
};
|
||||
}
|
||||
|
||||
public interface Transaction extends Closeable {
|
||||
@Override
|
||||
void close();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -102,7 +102,6 @@ public abstract class MessageDatabase extends Database implements MmsSmsColumns
|
|||
public abstract void markExpireStarted(Collection<Long> messageId, long startTime);
|
||||
|
||||
public abstract void markAsEndSession(long id);
|
||||
public abstract void markAsPreKeyBundle(long id);
|
||||
public abstract void markAsInvalidVersionKeyExchange(long id);
|
||||
public abstract void markAsSecure(long id);
|
||||
public abstract void markAsInsecure(long id);
|
||||
|
@ -111,7 +110,6 @@ public abstract class MessageDatabase extends Database implements MmsSmsColumns
|
|||
public abstract void markAsRateLimited(long id);
|
||||
public abstract void clearRateLimitStatus(Collection<Long> ids);
|
||||
public abstract void markAsDecryptFailed(long id);
|
||||
public abstract void markAsDecryptDuplicate(long id);
|
||||
public abstract void markAsNoSession(long id);
|
||||
public abstract void markAsUnsupportedProtocolVersion(long id);
|
||||
public abstract void markAsInvalidMessage(long id);
|
||||
|
@ -119,8 +117,8 @@ public abstract class MessageDatabase extends Database implements MmsSmsColumns
|
|||
public abstract void markAsOutbox(long id);
|
||||
public abstract void markAsPendingInsecureSmsFallback(long id);
|
||||
public abstract void markAsSent(long messageId, boolean secure);
|
||||
public abstract void markAsSentFailed(long id);
|
||||
public abstract void markUnidentified(long messageId, boolean unidentified);
|
||||
public abstract void markAsSentFailed(long id);
|
||||
public abstract void markAsSending(long messageId);
|
||||
public abstract void markAsRemoteDelete(long messageId);
|
||||
public abstract void markAsMissedCall(long id, boolean isVideoOffer);
|
||||
|
|
|
@ -56,6 +56,7 @@ import org.thoughtcrime.securesms.database.model.SmsMessageRecord;
|
|||
import org.thoughtcrime.securesms.database.model.databaseprotos.BodyRangeList;
|
||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||
import org.thoughtcrime.securesms.groups.GroupMigrationMembershipChange;
|
||||
import org.thoughtcrime.securesms.jobs.ThreadUpdateJob;
|
||||
import org.thoughtcrime.securesms.jobs.TrimThreadJob;
|
||||
import org.thoughtcrime.securesms.linkpreview.LinkPreview;
|
||||
import org.thoughtcrime.securesms.mms.IncomingMediaMessage;
|
||||
|
@ -296,11 +297,6 @@ public class MmsDatabase extends MessageDatabase {
|
|||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void markAsPreKeyBundle(long id) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void markAsInvalidVersionKeyExchange(long id) {
|
||||
throw new UnsupportedOperationException();
|
||||
|
@ -321,11 +317,6 @@ public class MmsDatabase extends MessageDatabase {
|
|||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void markAsDecryptDuplicate(long id) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void markAsNoSession(long id) {
|
||||
throw new UnsupportedOperationException();
|
||||
|
@ -759,7 +750,7 @@ public class MmsDatabase extends MessageDatabase {
|
|||
" WHERE " + ID + " = ?", new String[] {id + ""});
|
||||
|
||||
if (threadId.isPresent()) {
|
||||
DatabaseFactory.getThreadDatabase(context).update(threadId.get(), false);
|
||||
DatabaseFactory.getThreadDatabase(context).updateSnippetTypeSilently(threadId.get());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1352,7 +1343,7 @@ public class MmsDatabase extends MessageDatabase {
|
|||
|
||||
if (!Types.isExpirationTimerUpdate(mailbox)) {
|
||||
DatabaseFactory.getThreadDatabase(context).incrementUnread(threadId, 1);
|
||||
DatabaseFactory.getThreadDatabase(context).update(threadId, true);
|
||||
ThreadUpdateJob.enqueue(threadId);
|
||||
}
|
||||
|
||||
notifyConversationListeners(threadId);
|
||||
|
@ -1445,12 +1436,13 @@ public class MmsDatabase extends MessageDatabase {
|
|||
@Override
|
||||
public void markIncomingNotificationReceived(long threadId) {
|
||||
notifyConversationListeners(threadId);
|
||||
DatabaseFactory.getThreadDatabase(context).update(threadId, true);
|
||||
|
||||
if (org.thoughtcrime.securesms.util.Util.isDefaultSmsProvider(context)) {
|
||||
DatabaseFactory.getThreadDatabase(context).incrementUnread(threadId, 1);
|
||||
}
|
||||
|
||||
ThreadUpdateJob.enqueue(threadId);
|
||||
|
||||
TrimThreadJob.enqueueAsync(threadId);
|
||||
}
|
||||
|
||||
|
@ -1658,9 +1650,11 @@ public class MmsDatabase extends MessageDatabase {
|
|||
insertListener.onComplete();
|
||||
}
|
||||
|
||||
notifyConversationListeners(contentValues.getAsLong(THREAD_ID));
|
||||
DatabaseFactory.getThreadDatabase(context).setLastScrolled(contentValues.getAsLong(THREAD_ID), 0);
|
||||
DatabaseFactory.getThreadDatabase(context).update(contentValues.getAsLong(THREAD_ID), true);
|
||||
long contentValuesThreadId = contentValues.getAsLong(THREAD_ID);
|
||||
|
||||
notifyConversationListeners(contentValuesThreadId);
|
||||
DatabaseFactory.getThreadDatabase(context).setLastScrolled(contentValuesThreadId, 0);
|
||||
ThreadUpdateJob.enqueue(contentValuesThreadId);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -44,6 +44,7 @@ import org.thoughtcrime.securesms.database.model.databaseprotos.GroupCallUpdateD
|
|||
import org.thoughtcrime.securesms.database.model.databaseprotos.ProfileChangeDetails;
|
||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||
import org.thoughtcrime.securesms.groups.GroupMigrationMembershipChange;
|
||||
import org.thoughtcrime.securesms.jobs.ThreadUpdateJob;
|
||||
import org.thoughtcrime.securesms.jobs.TrimThreadJob;
|
||||
import org.thoughtcrime.securesms.mms.IncomingMediaMessage;
|
||||
import org.thoughtcrime.securesms.mms.MmsException;
|
||||
|
@ -58,6 +59,7 @@ import org.thoughtcrime.securesms.util.Base64;
|
|||
import org.thoughtcrime.securesms.util.CursorUtil;
|
||||
import org.thoughtcrime.securesms.util.JsonUtils;
|
||||
import org.thoughtcrime.securesms.util.SqlUtil;
|
||||
import org.thoughtcrime.securesms.util.Stopwatch;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
import org.whispersystems.libsignal.util.Pair;
|
||||
|
@ -177,14 +179,24 @@ public class SmsDatabase extends MessageDatabase {
|
|||
|
||||
private void updateTypeBitmask(long id, long maskOff, long maskOn) {
|
||||
SQLiteDatabase db = databaseHelper.getSignalWritableDatabase();
|
||||
db.execSQL("UPDATE " + TABLE_NAME +
|
||||
" SET " + TYPE + " = (" + TYPE + " & " + (Types.TOTAL_MASK - maskOff) + " | " + maskOn + " )" +
|
||||
" WHERE " + ID + " = ?", SqlUtil.buildArgs(id));
|
||||
|
||||
long threadId = getThreadIdForMessage(id);
|
||||
DatabaseFactory.getThreadDatabase(context).updateSnippetTypeSilently(threadId);
|
||||
long threadId;
|
||||
|
||||
db.beginTransaction();
|
||||
try {
|
||||
db.execSQL("UPDATE " + TABLE_NAME +
|
||||
" SET " + TYPE + " = (" + TYPE + " & " + (Types.TOTAL_MASK - maskOff) + " | " + maskOn + " )" +
|
||||
" WHERE " + ID + " = ?", SqlUtil.buildArgs(id));
|
||||
|
||||
threadId = getThreadIdForMessage(id);
|
||||
|
||||
DatabaseFactory.getThreadDatabase(context).updateSnippetTypeSilently(threadId);
|
||||
|
||||
db.setTransactionSuccessful();
|
||||
} finally {
|
||||
db.endTransaction();
|
||||
}
|
||||
|
||||
notifyConversationListListeners();
|
||||
notifyConversationListeners(threadId);
|
||||
}
|
||||
|
||||
|
@ -267,11 +279,6 @@ public class SmsDatabase extends MessageDatabase {
|
|||
updateTypeBitmask(id, Types.KEY_EXCHANGE_MASK, Types.END_SESSION_BIT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void markAsPreKeyBundle(long id) {
|
||||
updateTypeBitmask(id, Types.KEY_EXCHANGE_MASK, Types.KEY_EXCHANGE_BIT | Types.KEY_EXCHANGE_BUNDLE_BIT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void markAsInvalidVersionKeyExchange(long id) {
|
||||
updateTypeBitmask(id, 0, Types.KEY_EXCHANGE_INVALID_VERSION_BIT);
|
||||
|
@ -323,11 +330,6 @@ public class SmsDatabase extends MessageDatabase {
|
|||
updateTypeBitmask(id, Types.ENCRYPTION_MASK, Types.ENCRYPTION_REMOTE_FAILED_BIT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void markAsDecryptDuplicate(long id) {
|
||||
updateTypeBitmask(id, Types.ENCRYPTION_MASK, Types.ENCRYPTION_REMOTE_DUPLICATE_BIT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void markAsNoSession(long id) {
|
||||
updateTypeBitmask(id, Types.ENCRYPTION_MASK, Types.ENCRYPTION_REMOTE_NO_SESSION_BIT);
|
||||
|
@ -656,9 +658,8 @@ public class SmsDatabase extends MessageDatabase {
|
|||
|
||||
long threadId = getThreadIdForMessage(messageId);
|
||||
|
||||
DatabaseFactory.getThreadDatabase(context).update(threadId, true);
|
||||
ThreadUpdateJob.enqueue(threadId);
|
||||
notifyConversationListeners(threadId);
|
||||
notifyConversationListListeners();
|
||||
|
||||
return new InsertResult(messageId, threadId);
|
||||
}
|
||||
|
@ -741,7 +742,7 @@ public class SmsDatabase extends MessageDatabase {
|
|||
DatabaseFactory.getThreadDatabase(context).incrementUnread(threadId, 1);
|
||||
}
|
||||
|
||||
DatabaseFactory.getThreadDatabase(context).update(threadId, true);
|
||||
ThreadUpdateJob.enqueue(threadId);
|
||||
|
||||
db.setTransactionSuccessful();
|
||||
} finally {
|
||||
|
@ -818,7 +819,7 @@ public class SmsDatabase extends MessageDatabase {
|
|||
DatabaseFactory.getThreadDatabase(context).incrementUnread(threadId, 1);
|
||||
}
|
||||
|
||||
DatabaseFactory.getThreadDatabase(context).update(threadId, true);
|
||||
ThreadUpdateJob.enqueue(threadId);
|
||||
|
||||
db.setTransactionSuccessful();
|
||||
} finally {
|
||||
|
@ -883,14 +884,15 @@ public class SmsDatabase extends MessageDatabase {
|
|||
values.put(TYPE, type);
|
||||
values.put(THREAD_ID, threadId);
|
||||
|
||||
SQLiteDatabase db = databaseHelper.getSignalWritableDatabase();
|
||||
long messageId = db.insert(TABLE_NAME, null, values);
|
||||
SQLiteDatabase db = databaseHelper.getSignalWritableDatabase();
|
||||
long messageId = db.insert(TABLE_NAME, null, values);
|
||||
|
||||
DatabaseFactory.getThreadDatabase(context).update(threadId, true);
|
||||
if (unread) {
|
||||
DatabaseFactory.getThreadDatabase(context).incrementUnread(threadId, 1);
|
||||
}
|
||||
|
||||
ThreadUpdateJob.enqueue(threadId);
|
||||
|
||||
notifyConversationListeners(threadId);
|
||||
TrimThreadJob.enqueueAsync(threadId);
|
||||
|
||||
|
@ -1109,7 +1111,7 @@ public class SmsDatabase extends MessageDatabase {
|
|||
}
|
||||
|
||||
if (!silent) {
|
||||
DatabaseFactory.getThreadDatabase(context).update(threadId, true);
|
||||
ThreadUpdateJob.enqueue(threadId);
|
||||
}
|
||||
|
||||
if (message.getSubscriptionId() != -1) {
|
||||
|
@ -1152,7 +1154,7 @@ public class SmsDatabase extends MessageDatabase {
|
|||
long messageId = db.insert(TABLE_NAME, null, values);
|
||||
|
||||
DatabaseFactory.getThreadDatabase(context).incrementUnread(threadId, 1);
|
||||
DatabaseFactory.getThreadDatabase(context).update(threadId, true);
|
||||
ThreadUpdateJob.enqueue(threadId);
|
||||
|
||||
notifyConversationListeners(threadId);
|
||||
|
||||
|
@ -1176,7 +1178,7 @@ public class SmsDatabase extends MessageDatabase {
|
|||
databaseHelper.getSignalWritableDatabase().insert(TABLE_NAME, null, values);
|
||||
|
||||
DatabaseFactory.getThreadDatabase(context).incrementUnread(threadId, 1);
|
||||
DatabaseFactory.getThreadDatabase(context).update(threadId, true);
|
||||
ThreadUpdateJob.enqueue(threadId);
|
||||
|
||||
notifyConversationListeners(threadId);
|
||||
|
||||
|
@ -1226,7 +1228,6 @@ public class SmsDatabase extends MessageDatabase {
|
|||
|
||||
if (!message.isIdentityVerified() && !message.isIdentityDefault()) {
|
||||
DatabaseFactory.getThreadDatabase(context).setLastScrolled(threadId, 0);
|
||||
DatabaseFactory.getThreadDatabase(context).updateSilently(threadId, true);
|
||||
DatabaseFactory.getThreadDatabase(context).setLastSeenSilently(threadId);
|
||||
}
|
||||
|
||||
|
@ -1237,7 +1238,6 @@ public class SmsDatabase extends MessageDatabase {
|
|||
}
|
||||
|
||||
notifyConversationListeners(threadId);
|
||||
notifyConversationListListeners();
|
||||
|
||||
if (!message.isIdentityVerified() && !message.isIdentityDefault()) {
|
||||
TrimThreadJob.enqueueAsync(threadId);
|
||||
|
|
|
@ -224,8 +224,6 @@ public class ThreadDatabase extends Database {
|
|||
StorageSyncHelper.scheduleSyncForDataChange();
|
||||
}
|
||||
}
|
||||
|
||||
notifyConversationListListeners();
|
||||
}
|
||||
|
||||
public void updateSnippet(long threadId, String snippet, @Nullable Uri attachment, long date, long type, boolean unarchive) {
|
||||
|
|
|
@ -13,6 +13,7 @@ import androidx.annotation.RequiresApi;
|
|||
import com.annimon.stream.Collectors;
|
||||
import com.annimon.stream.Stream;
|
||||
|
||||
import org.signal.core.util.concurrent.SignalExecutors;
|
||||
import org.signal.core.util.logging.Log;
|
||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||
|
||||
|
@ -33,32 +34,34 @@ public final class JobSchedulerScheduler implements Scheduler {
|
|||
@RequiresApi(26)
|
||||
@Override
|
||||
public void schedule(long delay, @NonNull List<Constraint> constraints) {
|
||||
JobScheduler jobScheduler = application.getSystemService(JobScheduler.class);
|
||||
SignalExecutors.BOUNDED.execute(() -> {
|
||||
JobScheduler jobScheduler = application.getSystemService(JobScheduler.class);
|
||||
|
||||
String constraintNames = constraints.isEmpty() ? ""
|
||||
: Stream.of(constraints)
|
||||
.map(Constraint::getJobSchedulerKeyPart)
|
||||
.withoutNulls()
|
||||
.sorted()
|
||||
.collect(Collectors.joining("-"));
|
||||
String constraintNames = constraints.isEmpty() ? ""
|
||||
: Stream.of(constraints)
|
||||
.map(Constraint::getJobSchedulerKeyPart)
|
||||
.withoutNulls()
|
||||
.sorted()
|
||||
.collect(Collectors.joining("-"));
|
||||
|
||||
int jobId = constraintNames.hashCode();
|
||||
int jobId = constraintNames.hashCode();
|
||||
|
||||
if (jobScheduler.getPendingJob(jobId) != null) {
|
||||
return;
|
||||
}
|
||||
if (jobScheduler.getPendingJob(jobId) != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Log.i(TAG, String.format(Locale.US, "JobScheduler enqueue of %s (%d)", constraintNames, jobId));
|
||||
Log.i(TAG, String.format(Locale.US, "JobScheduler enqueue of %s (%d)", constraintNames, jobId));
|
||||
|
||||
JobInfo.Builder jobInfoBuilder = new JobInfo.Builder(jobId, new ComponentName(application, SystemService.class))
|
||||
.setMinimumLatency(delay)
|
||||
.setPersisted(true);
|
||||
JobInfo.Builder jobInfoBuilder = new JobInfo.Builder(jobId, new ComponentName(application, SystemService.class))
|
||||
.setMinimumLatency(delay)
|
||||
.setPersisted(true);
|
||||
|
||||
for (Constraint constraint : constraints) {
|
||||
constraint.applyToJobInfo(jobInfoBuilder);
|
||||
}
|
||||
for (Constraint constraint : constraints) {
|
||||
constraint.applyToJobInfo(jobInfoBuilder);
|
||||
}
|
||||
|
||||
jobScheduler.schedule(jobInfoBuilder.build());
|
||||
jobScheduler.schedule(jobInfoBuilder.build());
|
||||
});
|
||||
}
|
||||
|
||||
@RequiresApi(api = 26)
|
||||
|
|
|
@ -162,6 +162,7 @@ public final class JobManagerFactories {
|
|||
put(StorageForcePushJob.KEY, new StorageForcePushJob.Factory());
|
||||
put(StorageSyncJob.KEY, new StorageSyncJob.Factory());
|
||||
put(SubmitRateLimitPushChallengeJob.KEY, new SubmitRateLimitPushChallengeJob.Factory());
|
||||
put(ThreadUpdateJob.KEY, new ThreadUpdateJob.Factory());
|
||||
put(TrimThreadJob.KEY, new TrimThreadJob.Factory());
|
||||
put(TypingSendJob.KEY, new TypingSendJob.Factory());
|
||||
put(UpdateApkJob.KEY, new UpdateApkJob.Factory());
|
||||
|
|
|
@ -16,6 +16,7 @@ import org.thoughtcrime.securesms.recipients.RecipientUtil;
|
|||
import org.thoughtcrime.securesms.transport.RetryLaterException;
|
||||
import org.whispersystems.libsignal.util.guava.Optional;
|
||||
import org.whispersystems.signalservice.api.SignalServiceMessageSender;
|
||||
import org.whispersystems.signalservice.api.SignalServiceMessageSender.IndividualSendEvents;
|
||||
import org.whispersystems.signalservice.api.crypto.ContentHint;
|
||||
import org.whispersystems.signalservice.api.crypto.UnidentifiedAccessPair;
|
||||
import org.whispersystems.signalservice.api.messages.SendMessageResult;
|
||||
|
@ -109,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);
|
||||
SendMessageResult sendMessageResult = messageSender.sendDataMessage(address, unidentifiedAccess, ContentHint.DEFAULT, dataMessage, IndividualSendEvents.EMPTY);
|
||||
|
||||
if (sendMessageResult.getIdentityFailure() != null) {
|
||||
Log.w(TAG, "Identity failure for " + recipient.getId());
|
||||
|
|
|
@ -20,6 +20,7 @@ import org.thoughtcrime.securesms.recipients.RecipientId;
|
|||
import org.thoughtcrime.securesms.recipients.RecipientUtil;
|
||||
import org.whispersystems.libsignal.util.guava.Optional;
|
||||
import org.whispersystems.signalservice.api.SignalServiceMessageSender;
|
||||
import org.whispersystems.signalservice.api.SignalServiceMessageSender.IndividualSendEvents;
|
||||
import org.whispersystems.signalservice.api.crypto.ContentHint;
|
||||
import org.whispersystems.signalservice.api.crypto.UntrustedIdentityException;
|
||||
import org.whispersystems.signalservice.api.messages.SignalServiceAttachment;
|
||||
|
@ -137,7 +138,8 @@ public class PushGroupUpdateJob extends BaseJob {
|
|||
messageSender.sendDataMessage(RecipientUtil.toSignalServiceAddress(context, sourceRecipient),
|
||||
UnidentifiedAccessUtil.getAccessFor(context, sourceRecipient),
|
||||
ContentHint.DEFAULT,
|
||||
message);
|
||||
message,
|
||||
IndividualSendEvents.EMPTY);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -33,6 +33,7 @@ import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
|||
import org.thoughtcrime.securesms.util.Util;
|
||||
import org.whispersystems.libsignal.util.guava.Optional;
|
||||
import org.whispersystems.signalservice.api.SignalServiceMessageSender;
|
||||
import org.whispersystems.signalservice.api.SignalServiceMessageSender.IndividualSendEvents;
|
||||
import org.whispersystems.signalservice.api.crypto.ContentHint;
|
||||
import org.whispersystems.signalservice.api.crypto.UnidentifiedAccessPair;
|
||||
import org.whispersystems.signalservice.api.crypto.UntrustedIdentityException;
|
||||
|
@ -233,7 +234,7 @@ public class PushMediaSendJob extends PushSendJob {
|
|||
DatabaseFactory.getMessageLogDatabase(context).insertIfPossible(messageRecipient.getId(), message.getSentTimeMillis(), result, ContentHint.RESENDABLE, new MessageId(messageId, true));
|
||||
return syncAccess.isPresent();
|
||||
} else {
|
||||
SendMessageResult result = messageSender.sendDataMessage(address, UnidentifiedAccessUtil.getAccessFor(context, messageRecipient), ContentHint.RESENDABLE, mediaMessage);
|
||||
SendMessageResult result = messageSender.sendDataMessage(address, UnidentifiedAccessUtil.getAccessFor(context, messageRecipient), ContentHint.RESENDABLE, mediaMessage, IndividualSendEvents.EMPTY);
|
||||
DatabaseFactory.getMessageLogDatabase(context).insertIfPossible(messageRecipient.getId(), message.getSentTimeMillis(), result, ContentHint.RESENDABLE, new MessageId(messageId, true));
|
||||
return result.getSuccess().isUnidentified();
|
||||
}
|
||||
|
|
|
@ -47,7 +47,7 @@ public class PushTextSendJob extends PushSendJob {
|
|||
|
||||
private static final String KEY_MESSAGE_ID = "message_id";
|
||||
|
||||
private long messageId;
|
||||
private final long messageId;
|
||||
|
||||
public PushTextSendJob(long messageId, @NonNull Recipient recipient) {
|
||||
this(constructParameters(recipient, false), messageId);
|
||||
|
@ -91,35 +91,37 @@ public class PushTextSendJob extends PushSendJob {
|
|||
|
||||
RecipientUtil.shareProfileIfFirstSecureMessage(context, record.getRecipient());
|
||||
|
||||
Recipient recipient = record.getRecipient().fresh();
|
||||
Recipient recipient = record.getRecipient().resolve();
|
||||
byte[] profileKey = recipient.getProfileKey();
|
||||
UnidentifiedAccessMode accessMode = recipient.getUnidentifiedAccessMode();
|
||||
|
||||
boolean unidentified = deliver(record);
|
||||
|
||||
database.markAsSent(messageId, true);
|
||||
database.markUnidentified(messageId, unidentified);
|
||||
try (DatabaseFactory.Transaction unused = DatabaseFactory.getInstance(context).transaction()) {
|
||||
database.markAsSent(messageId, true);
|
||||
database.markUnidentified(messageId, unidentified);
|
||||
|
||||
if (recipient.isSelf()) {
|
||||
SyncMessageId id = new SyncMessageId(recipient.getId(), record.getDateSent());
|
||||
DatabaseFactory.getMmsSmsDatabase(context).incrementDeliveryReceiptCount(id, System.currentTimeMillis());
|
||||
DatabaseFactory.getMmsSmsDatabase(context).incrementReadReceiptCount(id, System.currentTimeMillis());
|
||||
}
|
||||
if (recipient.isSelf()) {
|
||||
SyncMessageId id = new SyncMessageId(recipient.getId(), record.getDateSent());
|
||||
DatabaseFactory.getMmsSmsDatabase(context).incrementDeliveryReceiptCount(id, System.currentTimeMillis());
|
||||
DatabaseFactory.getMmsSmsDatabase(context).incrementReadReceiptCount(id, System.currentTimeMillis());
|
||||
}
|
||||
|
||||
if (unidentified && accessMode == UnidentifiedAccessMode.UNKNOWN && profileKey == null) {
|
||||
log(TAG, String.valueOf(record.getDateSent()), "Marking recipient as UD-unrestricted following a UD send.");
|
||||
DatabaseFactory.getRecipientDatabase(context).setUnidentifiedAccessMode(recipient.getId(), UnidentifiedAccessMode.UNRESTRICTED);
|
||||
} else if (unidentified && accessMode == UnidentifiedAccessMode.UNKNOWN) {
|
||||
log(TAG, String.valueOf(record.getDateSent()), "Marking recipient as UD-enabled following a UD send.");
|
||||
DatabaseFactory.getRecipientDatabase(context).setUnidentifiedAccessMode(recipient.getId(), UnidentifiedAccessMode.ENABLED);
|
||||
} else if (!unidentified && accessMode != UnidentifiedAccessMode.DISABLED) {
|
||||
log(TAG, String.valueOf(record.getDateSent()), "Marking recipient as UD-disabled following a non-UD send.");
|
||||
DatabaseFactory.getRecipientDatabase(context).setUnidentifiedAccessMode(recipient.getId(), UnidentifiedAccessMode.DISABLED);
|
||||
}
|
||||
if (unidentified && accessMode == UnidentifiedAccessMode.UNKNOWN && profileKey == null) {
|
||||
log(TAG, String.valueOf(record.getDateSent()), "Marking recipient as UD-unrestricted following a UD send.");
|
||||
DatabaseFactory.getRecipientDatabase(context).setUnidentifiedAccessMode(recipient.getId(), UnidentifiedAccessMode.UNRESTRICTED);
|
||||
} else if (unidentified && accessMode == UnidentifiedAccessMode.UNKNOWN) {
|
||||
log(TAG, String.valueOf(record.getDateSent()), "Marking recipient as UD-enabled following a UD send.");
|
||||
DatabaseFactory.getRecipientDatabase(context).setUnidentifiedAccessMode(recipient.getId(), UnidentifiedAccessMode.ENABLED);
|
||||
} else if (!unidentified && accessMode != UnidentifiedAccessMode.DISABLED) {
|
||||
log(TAG, String.valueOf(record.getDateSent()), "Marking recipient as UD-disabled following a non-UD send.");
|
||||
DatabaseFactory.getRecipientDatabase(context).setUnidentifiedAccessMode(recipient.getId(), UnidentifiedAccessMode.DISABLED);
|
||||
}
|
||||
|
||||
if (record.getExpiresIn() > 0) {
|
||||
database.markExpireStarted(messageId);
|
||||
expirationManager.scheduleDeletion(record.getId(), record.isMms(), record.getExpiresIn());
|
||||
if (record.getExpiresIn() > 0) {
|
||||
database.markExpireStarted(messageId);
|
||||
expirationManager.scheduleDeletion(record.getId(), record.isMms(), record.getExpiresIn());
|
||||
}
|
||||
}
|
||||
|
||||
log(TAG, String.valueOf(record.getDateSent()), "Sent message: " + messageId);
|
||||
|
@ -167,7 +169,7 @@ public class PushTextSendJob extends PushSendJob {
|
|||
try {
|
||||
rotateSenderCertificateIfNecessary();
|
||||
|
||||
Recipient messageRecipient = message.getIndividualRecipient().fresh();
|
||||
Recipient messageRecipient = message.getIndividualRecipient().resolve();
|
||||
|
||||
if (messageRecipient.isUnregistered()) {
|
||||
throw new UndeliverableMessageException(messageRecipient.getId() + " not registered!");
|
||||
|
@ -192,16 +194,14 @@ public class PushTextSendJob extends PushSendJob {
|
|||
Optional<UnidentifiedAccessPair> syncAccess = UnidentifiedAccessUtil.getAccessForSync(context);
|
||||
SignalServiceSyncMessage syncMessage = buildSelfSendSyncMessage(context, textSecureMessage, syncAccess);
|
||||
|
||||
SignalLocalMetrics.IndividualMessageSend.onNetworkStarted(messageId);
|
||||
SignalLocalMetrics.IndividualMessageSend.onDeliveryStarted(messageId);
|
||||
SendMessageResult result = messageSender.sendSyncMessage(syncMessage, syncAccess);
|
||||
SignalLocalMetrics.IndividualMessageSend.onNetworkFinished(messageId);
|
||||
|
||||
DatabaseFactory.getMessageLogDatabase(context).insertIfPossible(messageRecipient.getId(), message.getDateSent(), result, ContentHint.RESENDABLE, new MessageId(messageId, false));
|
||||
return syncAccess.isPresent();
|
||||
} else {
|
||||
SignalLocalMetrics.IndividualMessageSend.onNetworkStarted(messageId);
|
||||
SendMessageResult result = messageSender.sendDataMessage(address, unidentifiedAccess, ContentHint.RESENDABLE, textSecureMessage);
|
||||
SignalLocalMetrics.IndividualMessageSend.onNetworkFinished(messageId);
|
||||
SignalLocalMetrics.IndividualMessageSend.onDeliveryStarted(messageId);
|
||||
SendMessageResult result = messageSender.sendDataMessage(address, unidentifiedAccess, ContentHint.RESENDABLE, textSecureMessage, new MetricEventListener(messageId));
|
||||
|
||||
DatabaseFactory.getMessageLogDatabase(context).insertIfPossible(messageRecipient.getId(), message.getDateSent(), result, ContentHint.RESENDABLE, new MessageId(messageId, false));
|
||||
return result.getSuccess().isUnidentified();
|
||||
|
@ -218,6 +218,29 @@ public class PushTextSendJob extends PushSendJob {
|
|||
return data.getLong(KEY_MESSAGE_ID);
|
||||
}
|
||||
|
||||
private static class MetricEventListener implements SignalServiceMessageSender.IndividualSendEvents {
|
||||
private final long messageId;
|
||||
|
||||
private MetricEventListener(long messageId) {
|
||||
this.messageId = messageId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessageEncrypted() {
|
||||
SignalLocalMetrics.IndividualMessageSend.onMessageEncrypted(messageId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessageSent() {
|
||||
SignalLocalMetrics.IndividualMessageSend.onMessageSent(messageId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSyncMessageSent() {
|
||||
SignalLocalMetrics.IndividualMessageSend.onSyncMessageSent(messageId);
|
||||
}
|
||||
}
|
||||
|
||||
public static class Factory implements Job.Factory<PushTextSendJob> {
|
||||
@Override
|
||||
public @NonNull PushTextSendJob create(@NonNull Parameters parameters, @NonNull Data data) {
|
||||
|
|
|
@ -14,6 +14,7 @@ import org.thoughtcrime.securesms.recipients.Recipient;
|
|||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientUtil;
|
||||
import org.whispersystems.signalservice.api.SignalServiceMessageSender;
|
||||
import org.whispersystems.signalservice.api.SignalServiceMessageSender.IndividualSendEvents;
|
||||
import org.whispersystems.signalservice.api.crypto.ContentHint;
|
||||
import org.whispersystems.signalservice.api.crypto.UntrustedIdentityException;
|
||||
import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage;
|
||||
|
@ -94,7 +95,8 @@ public class RequestGroupInfoJob extends BaseJob {
|
|||
messageSender.sendDataMessage(RecipientUtil.toSignalServiceAddress(context, recipient),
|
||||
UnidentifiedAccessUtil.getAccessFor(context, recipient),
|
||||
ContentHint.IMPLICIT,
|
||||
message);
|
||||
message,
|
||||
IndividualSendEvents.EMPTY);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
package org.thoughtcrime.securesms.jobs;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import org.signal.core.util.ThreadUtil;
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||
import org.thoughtcrime.securesms.jobmanager.Data;
|
||||
import org.thoughtcrime.securesms.jobmanager.Job;
|
||||
|
||||
public final class ThreadUpdateJob extends BaseJob {
|
||||
|
||||
public static final String KEY = "ThreadUpdateJob";
|
||||
|
||||
private static final String KEY_THREAD_ID = "thread_id";
|
||||
|
||||
private final long threadId;
|
||||
|
||||
private ThreadUpdateJob(long threadId) {
|
||||
this(new Parameters.Builder()
|
||||
.setQueue("ThreadUpdateJob_" + threadId)
|
||||
.setMaxInstancesForQueue(2)
|
||||
.build(),
|
||||
threadId);
|
||||
}
|
||||
|
||||
private ThreadUpdateJob(@NonNull Parameters parameters, long threadId) {
|
||||
super(parameters);
|
||||
this.threadId = threadId;
|
||||
}
|
||||
|
||||
public static void enqueue(long threadId) {
|
||||
ApplicationDependencies.getJobManager().add(new ThreadUpdateJob(threadId));
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull Data serialize() {
|
||||
return new Data.Builder().putLong(KEY_THREAD_ID, threadId).build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull String getFactoryKey() {
|
||||
return KEY;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onRun() throws Exception {
|
||||
DatabaseFactory.getThreadDatabase(context).update(threadId, true);
|
||||
ThreadUtil.sleep(1000);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean onShouldRetry(@NonNull Exception e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure() {
|
||||
}
|
||||
|
||||
public static final class Factory implements Job.Factory<ThreadUpdateJob> {
|
||||
@Override
|
||||
public @NonNull ThreadUpdateJob create(@NonNull Parameters parameters, @NonNull Data data) {
|
||||
return new ThreadUpdateJob(parameters, data.getLong(KEY_THREAD_ID));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -82,6 +82,7 @@ import org.thoughtcrime.securesms.jobs.RetrieveProfileJob;
|
|||
import org.thoughtcrime.securesms.jobs.SendDeliveryReceiptJob;
|
||||
import org.thoughtcrime.securesms.jobs.SenderKeyDistributionSendJob;
|
||||
import org.thoughtcrime.securesms.jobs.StickerPackDownloadJob;
|
||||
import org.thoughtcrime.securesms.jobs.ThreadUpdateJob;
|
||||
import org.thoughtcrime.securesms.jobs.TrimThreadJob;
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
||||
import org.thoughtcrime.securesms.linkpreview.LinkPreview;
|
||||
|
@ -721,10 +722,13 @@ public final class MessageContentProcessor {
|
|||
|
||||
SecurityEvent.broadcastSecurityUpdateEvent(context);
|
||||
|
||||
long messageId = database.insertMessageOutbox(threadId, outgoingEndSessionMessage,
|
||||
false, message.getTimestamp(),
|
||||
null);
|
||||
long messageId = database.insertMessageOutbox(threadId,
|
||||
outgoingEndSessionMessage,
|
||||
false,
|
||||
message.getTimestamp(),
|
||||
null);
|
||||
database.markAsSent(messageId, true);
|
||||
ThreadUpdateJob.enqueue(threadId);
|
||||
}
|
||||
|
||||
return threadId;
|
||||
|
@ -1555,6 +1559,7 @@ public final class MessageContentProcessor {
|
|||
messageId = DatabaseFactory.getSmsDatabase(context).insertMessageOutbox(threadId, outgoingTextMessage, false, message.getTimestamp(), null);
|
||||
database = DatabaseFactory.getSmsDatabase(context);
|
||||
database.markUnidentified(messageId, isUnidentified(message, recipient));
|
||||
ThreadUpdateJob.enqueue(threadId);
|
||||
}
|
||||
|
||||
database.markAsSent(messageId, true);
|
||||
|
|
|
@ -245,6 +245,10 @@ public class RecipientUtil {
|
|||
|
||||
@WorkerThread
|
||||
public static void shareProfileIfFirstSecureMessage(@NonNull Context context, @NonNull Recipient recipient) {
|
||||
if (recipient.isProfileSharing()) {
|
||||
return;
|
||||
}
|
||||
|
||||
long threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdIfExistsFor(recipient.getId());
|
||||
|
||||
if (isPreMessageRequestThread(context, threadId)) {
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
*/
|
||||
package org.thoughtcrime.securesms.sms;
|
||||
|
||||
import android.app.Application;
|
||||
import android.content.Context;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
@ -61,6 +62,7 @@ import org.thoughtcrime.securesms.jobs.ReactionSendJob;
|
|||
import org.thoughtcrime.securesms.jobs.RemoteDeleteSendJob;
|
||||
import org.thoughtcrime.securesms.jobs.ResumableUploadSpecJob;
|
||||
import org.thoughtcrime.securesms.jobs.SmsSendJob;
|
||||
import org.thoughtcrime.securesms.jobs.ThreadUpdateJob;
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
||||
import org.thoughtcrime.securesms.linkpreview.LinkPreview;
|
||||
import org.thoughtcrime.securesms.mms.MmsException;
|
||||
|
@ -120,6 +122,7 @@ public class MessageSender {
|
|||
|
||||
sendTextMessage(context, recipient, forceSms, keyExchange, messageId);
|
||||
onMessageSent();
|
||||
ThreadUpdateJob.enqueue(threadId);
|
||||
|
||||
return allocatedThreadId;
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ import org.thoughtcrime.securesms.database.IdentityDatabase.IdentityRecord;
|
|||
import org.thoughtcrime.securesms.database.MessageDatabase;
|
||||
import org.thoughtcrime.securesms.database.MessageDatabase.InsertResult;
|
||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||
import org.thoughtcrime.securesms.jobs.ThreadUpdateJob;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||
import org.thoughtcrime.securesms.sms.IncomingIdentityDefaultMessage;
|
||||
|
@ -90,6 +91,7 @@ public final class IdentityUtil {
|
|||
else outgoing = new OutgoingIdentityDefaultMessage(recipient);
|
||||
|
||||
DatabaseFactory.getSmsDatabase(context).insertMessageOutbox(threadId, outgoing, false, time, null);
|
||||
ThreadUpdateJob.enqueue(threadId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -112,6 +114,7 @@ public final class IdentityUtil {
|
|||
|
||||
Log.i(TAG, "Inserting verified outbox...");
|
||||
DatabaseFactory.getSmsDatabase(context).insertMessageOutbox(threadId, outgoing, false, time, null);
|
||||
ThreadUpdateJob.enqueue(threadId);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -99,7 +99,9 @@ public final class SignalLocalMetrics {
|
|||
private static final String SPLIT_DB_INSERT = "db-insert";
|
||||
private static final String SPLIT_JOB_ENQUEUE = "job-enqueue";
|
||||
private static final String SPLIT_JOB_PRE_NETWORK = "job-pre-network";
|
||||
private static final String SPLIT_NETWORK = "network";
|
||||
private static final String SPLIT_ENCRYPT = "encrypt";
|
||||
private static final String SPLIT_NETWORK_MAIN = "network-main";
|
||||
private static final String SPLIT_NETWORK_SYNC = "network-sync";
|
||||
private static final String SPLIT_JOB_POST_NETWORK = "job-post-network";
|
||||
private static final String SPLIT_UI_UPDATE = "ui-update";
|
||||
|
||||
|
@ -123,14 +125,24 @@ public final class SignalLocalMetrics {
|
|||
LocalMetrics.getInstance().split(requireId(messageId), SPLIT_JOB_ENQUEUE);
|
||||
}
|
||||
|
||||
public static void onNetworkStarted(long messageId) {
|
||||
public static void onDeliveryStarted(long messageId) {
|
||||
if (!ID_MAP.containsKey(messageId)) return;
|
||||
LocalMetrics.getInstance().split(requireId(messageId), SPLIT_JOB_PRE_NETWORK);
|
||||
}
|
||||
|
||||
public static void onNetworkFinished(long messageId) {
|
||||
public static void onMessageEncrypted(long messageId) {
|
||||
if (!ID_MAP.containsKey(messageId)) return;
|
||||
LocalMetrics.getInstance().split(requireId(messageId), SPLIT_NETWORK);
|
||||
LocalMetrics.getInstance().split(requireId(messageId), SPLIT_ENCRYPT);
|
||||
}
|
||||
|
||||
public static void onMessageSent(long messageId) {
|
||||
if (!ID_MAP.containsKey(messageId)) return;
|
||||
LocalMetrics.getInstance().split(requireId(messageId), SPLIT_NETWORK_MAIN);
|
||||
}
|
||||
|
||||
public static void onSyncMessageSent(long messageId) {
|
||||
if (!ID_MAP.containsKey(messageId)) return;
|
||||
LocalMetrics.getInstance().split(requireId(messageId), SPLIT_NETWORK_SYNC);
|
||||
}
|
||||
|
||||
public static void onJobFinished(long messageId) {
|
||||
|
|
|
@ -319,15 +319,21 @@ public class SignalServiceMessageSender {
|
|||
public SendMessageResult sendDataMessage(SignalServiceAddress recipient,
|
||||
Optional<UnidentifiedAccessPair> unidentifiedAccess,
|
||||
ContentHint contentHint,
|
||||
SignalServiceDataMessage message)
|
||||
SignalServiceDataMessage message,
|
||||
IndividualSendEvents sendEvents)
|
||||
throws UntrustedIdentityException, IOException
|
||||
{
|
||||
Log.d(TAG, "[" + message.getTimestamp() + "] Sending a data message.");
|
||||
|
||||
Content content = createMessageContent(message);
|
||||
EnvelopeContent envelopeContent = EnvelopeContent.encrypted(content, contentHint, message.getGroupId());
|
||||
long timestamp = message.getTimestamp();
|
||||
SendMessageResult result = sendMessage(recipient, getTargetUnidentifiedAccess(unidentifiedAccess), timestamp, envelopeContent, false, null);
|
||||
|
||||
sendEvents.onMessageEncrypted();
|
||||
|
||||
long timestamp = message.getTimestamp();
|
||||
SendMessageResult result = sendMessage(recipient, getTargetUnidentifiedAccess(unidentifiedAccess), timestamp, envelopeContent, false, null);
|
||||
|
||||
sendEvents.onMessageSent();
|
||||
|
||||
if (result.getSuccess() != null && result.getSuccess().isNeedsSync()) {
|
||||
Content syncMessage = createMultiDeviceSentTranscriptContent(content, Optional.of(recipient), timestamp, Collections.singletonList(result), false);
|
||||
|
@ -336,6 +342,8 @@ public class SignalServiceMessageSender {
|
|||
sendMessage(localAddress, Optional.absent(), timestamp, syncMessageContent, false, null);
|
||||
}
|
||||
|
||||
sendEvents.onSyncMessageSent();
|
||||
|
||||
// TODO [greyson][session] Delete this when we delete the button
|
||||
if (message.isEndSession()) {
|
||||
store.deleteAllSessions(recipient.getUuid().toString());
|
||||
|
@ -2077,4 +2085,21 @@ public class SignalServiceMessageSender {
|
|||
public interface EventListener {
|
||||
void onSecurityEvent(SignalServiceAddress address);
|
||||
}
|
||||
|
||||
public interface IndividualSendEvents {
|
||||
IndividualSendEvents EMPTY = new IndividualSendEvents() {
|
||||
@Override
|
||||
public void onMessageEncrypted() { }
|
||||
|
||||
@Override
|
||||
public void onMessageSent() { }
|
||||
|
||||
@Override
|
||||
public void onSyncMessageSent() { }
|
||||
};
|
||||
|
||||
void onMessageEncrypted();
|
||||
void onMessageSent();
|
||||
void onSyncMessageSent();
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue