Support for syncing contact colors and block lists

Closes #5638
// FREEBIE
This commit is contained in:
Moxie Marlinspike
2016-08-26 16:53:23 -07:00
parent 0a569676f7
commit 32f5bd5336
9 changed files with 194 additions and 7 deletions

View File

@@ -0,0 +1,79 @@
package org.thoughtcrime.securesms.jobs;
import android.content.Context;
import org.thoughtcrime.securesms.crypto.MasterSecret;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.RecipientPreferenceDatabase;
import org.thoughtcrime.securesms.database.RecipientPreferenceDatabase.BlockedReader;
import org.thoughtcrime.securesms.dependencies.InjectableType;
import org.thoughtcrime.securesms.dependencies.TextSecureCommunicationModule.TextSecureMessageSenderFactory;
import org.thoughtcrime.securesms.jobs.requirements.MasterSecretRequirement;
import org.thoughtcrime.securesms.recipients.Recipients;
import org.whispersystems.jobqueue.JobParameters;
import org.whispersystems.jobqueue.requirements.NetworkRequirement;
import org.whispersystems.signalservice.api.SignalServiceMessageSender;
import org.whispersystems.signalservice.api.crypto.UntrustedIdentityException;
import org.whispersystems.signalservice.api.messages.multidevice.BlockedListMessage;
import org.whispersystems.signalservice.api.messages.multidevice.SignalServiceSyncMessage;
import org.whispersystems.signalservice.api.push.exceptions.PushNetworkException;
import java.io.IOException;
import java.util.LinkedList;
import java.util.List;
import javax.inject.Inject;
public class MultiDeviceBlockedUpdateJob extends MasterSecretJob implements InjectableType {
private static final long serialVersionUID = 1L;
private static final String TAG = MultiDeviceBlockedUpdateJob.class.getSimpleName();
@Inject transient TextSecureMessageSenderFactory messageSenderFactory;
public MultiDeviceBlockedUpdateJob(Context context) {
super(context, JobParameters.newBuilder()
.withRequirement(new NetworkRequirement(context))
.withRequirement(new MasterSecretRequirement(context))
.withGroupId(MultiDeviceBlockedUpdateJob.class.getSimpleName())
.withPersistence()
.create());
}
@Override
public void onRun(MasterSecret masterSecret)
throws IOException, UntrustedIdentityException
{
RecipientPreferenceDatabase database = DatabaseFactory.getRecipientPreferenceDatabase(context);
SignalServiceMessageSender messageSender = messageSenderFactory.create();
BlockedReader reader = database.readerForBlocked(database.getBlocked());
List<String> blocked = new LinkedList<>();
Recipients recipients;
while ((recipients = reader.getNext()) != null) {
if (recipients.isSingleRecipient()) {
blocked.add(recipients.getPrimaryRecipient().getNumber());
}
}
messageSender.sendMessage(SignalServiceSyncMessage.forBlocked(new BlockedListMessage(blocked)));
}
@Override
public boolean onShouldRetryThrowable(Exception exception) {
if (exception instanceof PushNetworkException) return true;
return false;
}
@Override
public void onAdded() {
}
@Override
public void onCanceled() {
}
}

View File

@@ -6,6 +6,7 @@ import android.database.Cursor;
import android.net.Uri;
import android.os.Build;
import android.provider.ContactsContract;
import android.text.TextUtils;
import android.util.Log;
import org.thoughtcrime.securesms.contacts.ContactAccessor;
@@ -14,6 +15,9 @@ import org.thoughtcrime.securesms.crypto.MasterSecret;
import org.thoughtcrime.securesms.dependencies.InjectableType;
import org.thoughtcrime.securesms.dependencies.TextSecureCommunicationModule.TextSecureMessageSenderFactory;
import org.thoughtcrime.securesms.jobs.requirements.MasterSecretRequirement;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientFactory;
import org.thoughtcrime.securesms.recipients.Recipients;
import org.whispersystems.jobqueue.JobParameters;
import org.whispersystems.jobqueue.requirements.NetworkRequirement;
import org.whispersystems.libsignal.util.guava.Optional;
@@ -43,18 +47,56 @@ public class MultiDeviceContactUpdateJob extends MasterSecretJob implements Inje
@Inject transient TextSecureMessageSenderFactory messageSenderFactory;
private final long recipientId;
public MultiDeviceContactUpdateJob(Context context) {
this(context, -1);
}
public MultiDeviceContactUpdateJob(Context context, long recipientId) {
super(context, JobParameters.newBuilder()
.withRequirement(new NetworkRequirement(context))
.withRequirement(new MasterSecretRequirement(context))
.withGroupId(MultiDeviceContactUpdateJob.class.getSimpleName())
.withPersistence()
.create());
this.recipientId = recipientId;
}
@Override
public void onRun(MasterSecret masterSecret)
throws IOException, UntrustedIdentityException, NetworkException
{
if (recipientId <= 0) generateFullContactUpdate();
else generateSingleContactUpdate(recipientId);
}
private void generateSingleContactUpdate(long recipientId)
throws IOException, UntrustedIdentityException, NetworkException
{
SignalServiceMessageSender messageSender = messageSenderFactory.create();
File contactDataFile = createTempFile("multidevice-contact-update");
try {
DeviceContactsOutputStream out = new DeviceContactsOutputStream(new FileOutputStream(contactDataFile));
Recipient recipient = RecipientFactory.getRecipientForId(context, recipientId, false);
out.write(new DeviceContact(recipient.getNumber(),
Optional.fromNullable(recipient.getName()),
getAvatar(recipient.getContactUri()),
Optional.fromNullable(recipient.getColor().serialize())));
out.close();
sendUpdate(messageSender, contactDataFile);
} finally {
if (contactDataFile != null) contactDataFile.delete();
}
}
private void generateFullContactUpdate()
throws IOException, UntrustedIdentityException, NetworkException
{
SignalServiceMessageSender messageSender = messageSenderFactory.create();
File contactDataFile = createTempFile("multidevice-contact-update");
@@ -67,8 +109,9 @@ public class MultiDeviceContactUpdateJob extends MasterSecretJob implements Inje
Uri contactUri = Uri.withAppendedPath(ContactsContract.Contacts.CONTENT_URI, String.valueOf(contactData.id));
String number = contactData.numbers.get(0).number;
Optional<String> name = Optional.fromNullable(contactData.name);
Optional<String> color = getColor(number);
out.write(new DeviceContact(number, name, getAvatar(contactUri)));
out.write(new DeviceContact(number, name, getAvatar(contactUri), color));
}
out.close();
@@ -95,6 +138,15 @@ public class MultiDeviceContactUpdateJob extends MasterSecretJob implements Inje
}
private Optional<String> getColor(String number) {
if (!TextUtils.isEmpty(number)) {
Recipients recipients = RecipientFactory.getRecipientsFromString(context, number, false);
return Optional.of(recipients.getColor().serialize());
} else {
return Optional.absent();
}
}
private void sendUpdate(SignalServiceMessageSender messageSender, File contactsFile)
throws IOException, UntrustedIdentityException, NetworkException
{

View File

@@ -286,6 +286,12 @@ public class PushDecryptJob extends ContextJob {
.getJobManager()
.add(new MultiDeviceGroupUpdateJob(getContext()));
}
if (message.isBlockedListRequest()) {
ApplicationContext.getInstance(context)
.getJobManager()
.add(new MultiDeviceBlockedUpdateJob(getContext()));
}
}
private void handleSynchronizeReadMessage(@NonNull MasterSecretUnion masterSecret,