Synchronize with paired devices when a contact changes.

// FREEBIE
This commit is contained in:
Moxie Marlinspike 2015-10-23 12:51:28 -07:00
parent 05eba8c2f0
commit 11a93fabe5
6 changed files with 46 additions and 21 deletions

View File

@ -26,6 +26,7 @@ import org.thoughtcrime.securesms.dependencies.InjectableType;
import org.thoughtcrime.securesms.util.DynamicLanguage;
import org.thoughtcrime.securesms.util.DynamicTheme;
import org.thoughtcrime.securesms.util.ProgressDialogAsyncTask;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.whispersystems.textsecure.api.TextSecureAccountManager;
import org.whispersystems.textsecure.api.messages.multidevice.DeviceInfo;
@ -122,8 +123,12 @@ public class DeviceListActivity extends PassphraseRequiredActionBarActivity {
setListAdapter(new DeviceListAdapter(getActivity(), R.layout.device_list_item_view, data));
if (data.isEmpty()) empty.setVisibility(View.VISIBLE);
else empty.setVisibility(View.GONE);
if (data.isEmpty()) {
empty.setVisibility(View.VISIBLE);
TextSecurePreferences.setMultiDevice(getActivity(), false);
} else {
empty.setVisibility(View.GONE);
}
}
@Override

View File

@ -20,6 +20,7 @@ import org.thoughtcrime.securesms.crypto.MasterSecret;
import org.thoughtcrime.securesms.push.TextSecureCommunicationFactory;
import org.thoughtcrime.securesms.util.Base64;
import org.thoughtcrime.securesms.util.ProgressDialogAsyncTask;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.whispersystems.libaxolotl.IdentityKeyPair;
import org.whispersystems.libaxolotl.InvalidKeyException;
import org.whispersystems.libaxolotl.ecc.Curve;
@ -111,6 +112,7 @@ public class DeviceProvisioningActivity extends PassphraseRequiredActionBarActiv
IdentityKeyPair identityKeyPair = IdentityKeyUtil.getIdentityKeyPair(context);
accountManager.addDevice(ephemeralId, publicKey, identityKeyPair, verificationCode);
TextSecurePreferences.setMultiDevice(context, true);
return SUCCESS;

View File

@ -70,7 +70,7 @@ public class ContactsDatabase {
this.context = context;
}
public synchronized void setRegisteredUsers(Account account, List<String> e164numbers)
public synchronized boolean setRegisteredUsers(Account account, List<String> e164numbers)
throws RemoteException, OperationApplicationException
{
Map<String, Long> currentContacts = new HashMap<>();
@ -111,6 +111,9 @@ public class ContactsDatabase {
if (!operations.isEmpty()) {
context.getContentResolver().applyBatch(ContactsContract.AUTHORITY, operations);
return true;
} else {
return false;
}
}

View File

@ -101,6 +101,7 @@ public class MultiDeviceContactUpdateJob extends MasterSecretJob implements Inje
private void sendUpdate(TextSecureMessageSender messageSender, File contactsFile)
throws IOException, UntrustedIdentityException, NetworkException
{
if (contactsFile.length() > 0) {
FileInputStream contactsFileStream = new FileInputStream(contactsFile);
TextSecureAttachmentStream attachmentStream = TextSecureAttachment.newStreamBuilder()
.withStream(contactsFileStream)
@ -114,6 +115,7 @@ public class MultiDeviceContactUpdateJob extends MasterSecretJob implements Inje
throw new NetworkException(ioe);
}
}
}
private Optional<TextSecureAttachmentStream> getAvatar(Uri uri) throws IOException {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {

View File

@ -15,6 +15,7 @@ import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.NotInDirectoryException;
import org.thoughtcrime.securesms.database.TextSecureDirectory;
import org.thoughtcrime.securesms.jobs.DirectoryRefreshJob;
import org.thoughtcrime.securesms.jobs.MultiDeviceContactUpdateJob;
import org.thoughtcrime.securesms.push.TextSecureCommunicationFactory;
import org.thoughtcrime.securesms.recipients.Recipients;
import org.thoughtcrime.securesms.util.DirectoryHelper.UserCapabilities.Capability;
@ -59,13 +60,9 @@ public class DirectoryHelper {
private static final String TAG = DirectoryHelper.class.getSimpleName();
public static void refreshDirectory(final Context context) throws IOException {
refreshDirectory(context, TextSecureCommunicationFactory.createManager(context));
}
public static void refreshDirectory(final Context context, final TextSecureAccountManager accountManager)
throws IOException
{
refreshDirectory(context, accountManager, TextSecurePreferences.getLocalNumber(context));
refreshDirectory(context,
TextSecureCommunicationFactory.createManager(context),
TextSecurePreferences.getLocalNumber(context));
}
public static void refreshDirectory(final Context context, final TextSecureAccountManager accountManager, final String localNumber)
@ -92,7 +89,14 @@ public class DirectoryHelper {
}
try {
DatabaseFactory.getContactsDatabase(context).setRegisteredUsers(account.get(), e164numbers);
boolean modified = DatabaseFactory.getContactsDatabase(context)
.setRegisteredUsers(account.get(), e164numbers);
if (modified && TextSecurePreferences.isMultiDevice(context)) {
ApplicationContext.getInstance(context)
.getJobManager()
.add(new MultiDeviceContactUpdateJob(context));
}
} catch (RemoteException | OperationApplicationException e) {
Log.w(TAG, e);
}

View File

@ -90,6 +90,15 @@ public class TextSecurePreferences {
public static final String MEDIA_DOWNLOAD_ROAMING_PREF = "pref_media_download_roaming";
public static final String SYSTEM_EMOJI_PREF = "pref_system_emoji";
private static final String MULTI_DEVICE_PROVISIONED_PREF = "pref_multi_device";
public static void setMultiDevice(Context context, boolean value) {
setBooleanPreference(context, MULTI_DEVICE_PROVISIONED_PREF, value);
}
public static boolean isMultiDevice(Context context) {
return getBooleanPreference(context, MULTI_DEVICE_PROVISIONED_PREF, false);
}
public static NotificationPrivacyPreference getNotificationPrivacy(Context context) {
return new NotificationPrivacyPreference(getStringPreference(context, NOTIFICATION_PRIVACY_PREF, "all"));