Support for synchronizing read state to/from desktop

// FREEBIE
This commit is contained in:
Moxie Marlinspike
2016-02-19 17:07:41 -08:00
parent f5c90df780
commit 08e2221dc0
15 changed files with 369 additions and 38 deletions

View File

@@ -0,0 +1,89 @@
package org.thoughtcrime.securesms.jobs;
import android.content.Context;
import org.thoughtcrime.securesms.crypto.MasterSecret;
import org.thoughtcrime.securesms.database.MessagingDatabase.SyncMessageId;
import org.thoughtcrime.securesms.dependencies.InjectableType;
import org.thoughtcrime.securesms.dependencies.TextSecureCommunicationModule;
import org.thoughtcrime.securesms.jobs.requirements.MasterSecretRequirement;
import org.whispersystems.jobqueue.JobParameters;
import org.whispersystems.jobqueue.requirements.NetworkRequirement;
import org.whispersystems.textsecure.api.TextSecureMessageSender;
import org.whispersystems.textsecure.api.crypto.UntrustedIdentityException;
import org.whispersystems.textsecure.api.messages.multidevice.ReadMessage;
import org.whispersystems.textsecure.api.messages.multidevice.TextSecureSyncMessage;
import org.whispersystems.textsecure.api.push.exceptions.PushNetworkException;
import java.io.IOException;
import java.io.Serializable;
import java.util.LinkedList;
import java.util.List;
import javax.inject.Inject;
public class MultiDeviceReadUpdateJob extends MasterSecretJob implements InjectableType {
private static final long serialVersionUID = 1L;
private static final String TAG = MultiDeviceReadUpdateJob.class.getSimpleName();
private final List<SerializableSyncMessageId> messageIds;
@Inject
transient TextSecureCommunicationModule.TextSecureMessageSenderFactory messageSenderFactory;
public MultiDeviceReadUpdateJob(Context context, List<SyncMessageId> messageIds) {
super(context, JobParameters.newBuilder()
.withRequirement(new NetworkRequirement(context))
.withRequirement(new MasterSecretRequirement(context))
.withPersistence()
.create());
this.messageIds = new LinkedList<>();
for (SyncMessageId messageId : messageIds) {
this.messageIds.add(new SerializableSyncMessageId(messageId.getAddress(), messageId.getTimetamp()));
}
}
@Override
public void onRun(MasterSecret masterSecret) throws IOException, UntrustedIdentityException {
List<ReadMessage> readMessages = new LinkedList<>();
for (SerializableSyncMessageId messageId : messageIds) {
readMessages.add(new ReadMessage(messageId.sender, messageId.timestamp));
}
TextSecureMessageSender messageSender = messageSenderFactory.create();
messageSender.sendMessage(TextSecureSyncMessage.forRead(readMessages));
}
@Override
public boolean onShouldRetryThrowable(Exception exception) {
return exception instanceof PushNetworkException;
}
@Override
public void onAdded() {
}
@Override
public void onCanceled() {
}
private static class SerializableSyncMessageId implements Serializable {
private static final long serialVersionUID = 1L;
private final String sender;
private final long timestamp;
private SerializableSyncMessageId(String sender, long timestamp) {
this.sender = sender;
this.timestamp = timestamp;
}
}
}

View File

@@ -17,6 +17,8 @@ import org.thoughtcrime.securesms.crypto.storage.TextSecureAxolotlStore;
import org.thoughtcrime.securesms.crypto.storage.TextSecureSessionStore;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.EncryptingSmsDatabase;
import org.thoughtcrime.securesms.database.MessagingDatabase;
import org.thoughtcrime.securesms.database.MessagingDatabase.SyncMessageId;
import org.thoughtcrime.securesms.database.MmsDatabase;
import org.thoughtcrime.securesms.database.NoSuchMessageException;
import org.thoughtcrime.securesms.database.PushDatabase;
@@ -56,6 +58,7 @@ import org.whispersystems.textsecure.api.messages.TextSecureContent;
import org.whispersystems.textsecure.api.messages.TextSecureDataMessage;
import org.whispersystems.textsecure.api.messages.TextSecureEnvelope;
import org.whispersystems.textsecure.api.messages.TextSecureGroup;
import org.whispersystems.textsecure.api.messages.multidevice.ReadMessage;
import org.whispersystems.textsecure.api.messages.multidevice.RequestMessage;
import org.whispersystems.textsecure.api.messages.multidevice.SentTranscriptMessage;
import org.whispersystems.textsecure.api.messages.multidevice.TextSecureSyncMessage;
@@ -146,6 +149,8 @@ public class PushDecryptJob extends ContextJob {
if (syncMessage.getSent().isPresent()) handleSynchronizeSentMessage(masterSecret, envelope, syncMessage.getSent().get(), smsMessageId);
else if (syncMessage.getRequest().isPresent()) handleSynchronizeRequestMessage(masterSecret, syncMessage.getRequest().get());
else if (syncMessage.getRead().isPresent()) handleSynchronizeReadMessage(masterSecret, syncMessage.getRead().get());
else Log.w(TAG, "Contains no known sync types...");
}
if (envelope.isPreKeyWhisperMessage()) {
@@ -252,6 +257,17 @@ public class PushDecryptJob extends ContextJob {
}
}
private void handleSynchronizeReadMessage(@NonNull MasterSecretUnion masterSecret,
@NonNull List<ReadMessage> readMessages)
{
for (ReadMessage readMessage : readMessages) {
DatabaseFactory.getSmsDatabase(context).setTimestampRead(new SyncMessageId(readMessage.getSender(), readMessage.getTimestamp()));
DatabaseFactory.getMmsDatabase(context).setTimestampRead(new SyncMessageId(readMessage.getSender(), readMessage.getTimestamp()));
}
MessageNotifier.updateNotification(context, masterSecret.getMasterSecret().orNull());
}
private void handleMediaMessage(@NonNull MasterSecretUnion masterSecret,
@NonNull TextSecureEnvelope envelope,
@NonNull TextSecureDataMessage message,

View File

@@ -5,6 +5,8 @@ import android.util.Log;
import org.thoughtcrime.securesms.ApplicationContext;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.MessagingDatabase;
import org.thoughtcrime.securesms.database.MessagingDatabase.SyncMessageId;
import org.thoughtcrime.securesms.database.NotInDirectoryException;
import org.thoughtcrime.securesms.database.TextSecureDirectory;
import org.thoughtcrime.securesms.recipients.RecipientFactory;
@@ -64,8 +66,8 @@ public abstract class PushReceivedJob extends ContextJob {
private void handleReceipt(TextSecureEnvelope envelope) {
Log.w(TAG, String.format("Received receipt: (XXXXX, %d)", envelope.getTimestamp()));
DatabaseFactory.getMmsSmsDatabase(context).incrementDeliveryReceiptCount(envelope.getSource(),
envelope.getTimestamp());
DatabaseFactory.getMmsSmsDatabase(context).incrementDeliveryReceiptCount(new SyncMessageId(envelope.getSource(),
envelope.getTimestamp()));
}
private boolean isActiveNumber(Context context, String e164number) {