Skip to content

Commit b136fed

Browse files
committed
Update contact DB on incoming messages
When we receive a Signal message from a previously unregistered user, reflect that in the contact DB. Fixes signalapp#3949 Closes signalapp#4492 // FREEBIE
1 parent fb8d6cb commit b136fed

5 files changed

Lines changed: 100 additions & 36 deletions

File tree

src/org/thoughtcrime/securesms/ConversationActivity.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@
3030
import android.graphics.drawable.ColorDrawable;
3131
import android.net.Uri;
3232
import android.os.AsyncTask;
33-
import android.os.Build;
3433
import android.os.Bundle;
3534
import android.provider.ContactsContract;
3635
import android.support.annotation.NonNull;
@@ -67,8 +66,6 @@
6766
import org.thoughtcrime.securesms.components.ComposeText;
6867
import org.thoughtcrime.securesms.components.InputAwareLayout;
6968
import org.thoughtcrime.securesms.components.KeyboardAwareLinearLayout.OnKeyboardShownListener;
70-
import org.thoughtcrime.securesms.components.reminder.InviteReminder;
71-
import org.thoughtcrime.securesms.components.reminder.ReminderView;
7269
import org.thoughtcrime.securesms.components.SendButton;
7370
import org.thoughtcrime.securesms.components.camera.HidingImageButton;
7471
import org.thoughtcrime.securesms.components.camera.QuickAttachmentDrawer;
@@ -77,6 +74,8 @@
7774
import org.thoughtcrime.securesms.components.emoji.EmojiDrawer;
7875
import org.thoughtcrime.securesms.components.emoji.EmojiDrawer.EmojiEventListener;
7976
import org.thoughtcrime.securesms.components.emoji.EmojiToggle;
77+
import org.thoughtcrime.securesms.components.reminder.InviteReminder;
78+
import org.thoughtcrime.securesms.components.reminder.ReminderView;
8079
import org.thoughtcrime.securesms.contacts.ContactAccessor;
8180
import org.thoughtcrime.securesms.contacts.ContactAccessor.ContactData;
8281
import org.thoughtcrime.securesms.crypto.MasterCipher;
@@ -110,7 +109,6 @@
110109
import org.thoughtcrime.securesms.sms.OutgoingEncryptedMessage;
111110
import org.thoughtcrime.securesms.sms.OutgoingEndSessionMessage;
112111
import org.thoughtcrime.securesms.sms.OutgoingTextMessage;
113-
import org.thoughtcrime.securesms.util.concurrent.AssertedSuccessListener;
114112
import org.thoughtcrime.securesms.util.CharacterCalculator.CharacterState;
115113
import org.thoughtcrime.securesms.util.Dialogs;
116114
import org.thoughtcrime.securesms.util.DirectoryHelper;
@@ -123,6 +121,7 @@
123121
import org.thoughtcrime.securesms.util.TextSecurePreferences;
124122
import org.thoughtcrime.securesms.util.Util;
125123
import org.thoughtcrime.securesms.util.ViewUtil;
124+
import org.thoughtcrime.securesms.util.concurrent.AssertedSuccessListener;
126125
import org.thoughtcrime.securesms.util.concurrent.ListenableFuture;
127126
import org.thoughtcrime.securesms.util.concurrent.SettableFuture;
128127
import org.whispersystems.libaxolotl.InvalidMessageException;
@@ -785,7 +784,8 @@ protected Pair<Boolean, Boolean> doInBackground(Recipients... params) {
785784
if (capabilities.getTextCapability() == Capability.UNKNOWN ||
786785
capabilities.getVoiceCapability() == Capability.UNKNOWN)
787786
{
788-
capabilities = DirectoryHelper.refreshDirectoryFor(context, recipients);
787+
capabilities = DirectoryHelper.refreshDirectoryFor(context, masterSecret, recipients,
788+
TextSecurePreferences.getLocalNumber(context));
789789
}
790790

791791
return new Pair<>(capabilities.getTextCapability() == Capability.SUPPORTED,

src/org/thoughtcrime/securesms/contacts/ContactsDatabase.java

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,8 @@ public ContactsDatabase(Context context) {
7777

7878
public synchronized @NonNull List<String> setRegisteredUsers(@NonNull Account account,
7979
@NonNull String localNumber,
80-
@NonNull List<ContactTokenDetails> registeredContacts)
80+
@NonNull List<ContactTokenDetails> registeredContacts,
81+
boolean remove)
8182
throws RemoteException, OperationApplicationException
8283
{
8384

@@ -107,8 +108,10 @@ public ContactsDatabase(Context context) {
107108
ContactTokenDetails tokenDetails = registeredNumbers.get(currentContactEntry.getKey());
108109

109110
if (tokenDetails == null) {
110-
Log.w(TAG, "Removing number: " + currentContactEntry.getKey());
111-
removeTextSecureRawContact(operations, account, currentContactEntry.getValue().getId());
111+
if (remove) {
112+
Log.w(TAG, "Removing number: " + currentContactEntry.getKey());
113+
removeTextSecureRawContact(operations, account, currentContactEntry.getValue().getId());
114+
}
112115
} else if (tokenDetails.isVoice() && !currentContactEntry.getValue().isVoiceSupported()) {
113116
Log.w(TAG, "Adding voice support: " + currentContactEntry.getKey());
114117
addContactVoiceSupport(operations, currentContactEntry.getKey(), currentContactEntry.getValue().getId());
@@ -298,7 +301,9 @@ private void removeTextSecureRawContact(List<ContentProviderOperation> operation
298301
.build());
299302
}
300303

301-
private @NonNull Map<String, SignalContact> getSignalRawContacts(Account account, String localNumber) {
304+
private @NonNull Map<String, SignalContact> getSignalRawContacts(@NonNull Account account,
305+
@NonNull String localNumber)
306+
{
302307
Uri currentContactsUri = RawContacts.CONTENT_URI.buildUpon()
303308
.appendQueryParameter(RawContacts.ACCOUNT_NAME, account.name)
304309
.appendQueryParameter(RawContacts.ACCOUNT_TYPE, account.type).build();

src/org/thoughtcrime/securesms/jobs/DirectoryRefreshJob.java

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,16 @@
22

33
import android.content.Context;
44
import android.os.PowerManager;
5+
import android.support.annotation.NonNull;
6+
import android.support.annotation.Nullable;
57
import android.util.Log;
68

9+
import org.thoughtcrime.securesms.crypto.MasterSecret;
710
import org.thoughtcrime.securesms.crypto.SecurityEvent;
11+
import org.thoughtcrime.securesms.recipients.Recipients;
812
import org.thoughtcrime.securesms.service.KeyCachingService;
913
import org.thoughtcrime.securesms.util.DirectoryHelper;
14+
import org.thoughtcrime.securesms.util.TextSecurePreferences;
1015
import org.whispersystems.jobqueue.JobParameters;
1116
import org.whispersystems.jobqueue.requirements.NetworkRequirement;
1217
import org.whispersystems.textsecure.api.push.exceptions.PushNetworkException;
@@ -15,11 +20,24 @@
1520

1621
public class DirectoryRefreshJob extends ContextJob {
1722

18-
public DirectoryRefreshJob(Context context) {
23+
@Nullable private transient Recipients recipients;
24+
@Nullable private transient MasterSecret masterSecret;
25+
26+
public DirectoryRefreshJob(@NonNull Context context) {
27+
this(context, null, null);
28+
}
29+
30+
public DirectoryRefreshJob(@NonNull Context context,
31+
@Nullable MasterSecret masterSecret,
32+
@Nullable Recipients recipients)
33+
{
1934
super(context, JobParameters.newBuilder()
2035
.withGroupId(DirectoryRefreshJob.class.getSimpleName())
2136
.withRequirement(new NetworkRequirement(context))
2237
.create());
38+
39+
this.recipients = recipients;
40+
this.masterSecret = masterSecret;
2341
}
2442

2543
@Override
@@ -33,7 +51,11 @@ public void onRun() throws IOException {
3351

3452
try {
3553
wakeLock.acquire();
36-
DirectoryHelper.refreshDirectory(context, KeyCachingService.getMasterSecret(context));
54+
if (recipients == null) {
55+
DirectoryHelper.refreshDirectory(context, KeyCachingService.getMasterSecret(context));
56+
} else {
57+
DirectoryHelper.refreshDirectoryFor(context, masterSecret, recipients, TextSecurePreferences.getLocalNumber(context));
58+
}
3759
SecurityEvent.broadcastSecurityUpdateEvent(context);
3860
} finally {
3961
if (wakeLock.isHeld()) wakeLock.release();

src/org/thoughtcrime/securesms/jobs/PushReceivedJob.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import org.thoughtcrime.securesms.database.TextSecureDirectory;
1010
import org.thoughtcrime.securesms.recipients.RecipientFactory;
1111
import org.thoughtcrime.securesms.recipients.Recipients;
12+
import org.thoughtcrime.securesms.service.KeyCachingService;
1213
import org.whispersystems.jobqueue.JobManager;
1314
import org.whispersystems.jobqueue.JobParameters;
1415
import org.whispersystems.textsecure.api.messages.TextSecureEnvelope;
@@ -29,6 +30,9 @@ public void handle(TextSecureEnvelope envelope, boolean sendExplicitReceipt) {
2930
contactTokenDetails.setNumber(envelope.getSource());
3031

3132
directory.setNumber(contactTokenDetails, true);
33+
34+
Recipients recipients = RecipientFactory.getRecipientsFromString(context, envelope.getSource(), false);
35+
ApplicationContext.getInstance(context).getJobManager().add(new DirectoryRefreshJob(context, KeyCachingService.getMasterSecret(context), recipients));
3236
}
3337

3438
if (envelope.isReceipt()) {

src/org/thoughtcrime/securesms/util/DirectoryHelper.java

Lines changed: 58 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,11 @@
1818
import org.thoughtcrime.securesms.database.DatabaseFactory;
1919
import org.thoughtcrime.securesms.database.NotInDirectoryException;
2020
import org.thoughtcrime.securesms.database.TextSecureDirectory;
21-
import org.thoughtcrime.securesms.jobs.DirectoryRefreshJob;
2221
import org.thoughtcrime.securesms.jobs.MultiDeviceContactUpdateJob;
2322
import org.thoughtcrime.securesms.notifications.MessageNotifier;
2423
import org.thoughtcrime.securesms.push.TextSecureCommunicationFactory;
2524
import org.thoughtcrime.securesms.recipients.Recipients;
26-
import org.thoughtcrime.securesms.sms.IncomingGroupMessage;
2725
import org.thoughtcrime.securesms.sms.IncomingJoinedMessage;
28-
import org.thoughtcrime.securesms.sms.MessageSender;
2926
import org.thoughtcrime.securesms.util.DirectoryHelper.UserCapabilities.Capability;
3027
import org.whispersystems.libaxolotl.util.guava.Optional;
3128
import org.whispersystems.textsecure.api.TextSecureAccountManager;
@@ -80,11 +77,7 @@ public static void refreshDirectory(@NonNull Context context, @Nullable MasterSe
8077
.add(new MultiDeviceContactUpdateJob(context));
8178
}
8279

83-
for (String newUser : newUsers) {
84-
IncomingJoinedMessage message = new IncomingJoinedMessage(newUser);
85-
Pair<Long, Long> smsAndThreadId = DatabaseFactory.getSmsDatabase(context).insertMessageInbox(message);
86-
MessageNotifier.updateNotification(context, masterSecret, smsAndThreadId.second);
87-
}
80+
notifyNewUsers(context, masterSecret, newUsers);
8881
}
8982

9083
public static @NonNull List<String> refreshDirectory(@NonNull Context context,
@@ -93,7 +86,6 @@ public static void refreshDirectory(@NonNull Context context, @Nullable MasterSe
9386
throws IOException
9487
{
9588
TextSecureDirectory directory = TextSecureDirectory.getInstance(context);
96-
Optional<Account> account = getOrCreateAccount(context);
9789
Set<String> eligibleContactNumbers = directory.getPushEligibleContactNumbers(localNumber);
9890
List<ContactTokenDetails> activeTokens = accountManager.getContacts(eligibleContactNumbers);
9991

@@ -104,33 +96,35 @@ public static void refreshDirectory(@NonNull Context context, @Nullable MasterSe
10496
}
10597

10698
directory.setNumbers(activeTokens, eligibleContactNumbers);
107-
108-
if (account.isPresent()) {
109-
try {
110-
return DatabaseFactory.getContactsDatabase(context)
111-
.setRegisteredUsers(account.get(), localNumber, activeTokens);
112-
} catch (RemoteException | OperationApplicationException e) {
113-
Log.w(TAG, e);
114-
}
115-
}
99+
return updateContactsDatabase(context, localNumber, activeTokens, true);
116100
}
117101

118102
return new LinkedList<>();
119103
}
120104

121-
public static UserCapabilities refreshDirectoryFor(Context context, Recipients recipients)
105+
public static UserCapabilities refreshDirectoryFor(@NonNull Context context,
106+
@Nullable MasterSecret masterSecret,
107+
@NonNull Recipients recipients,
108+
@NonNull String localNumber)
122109
throws IOException
123110
{
124111
try {
125-
TextSecureDirectory directory = TextSecureDirectory.getInstance(context);
126-
TextSecureAccountManager accountManager = TextSecureCommunicationFactory.createManager(context);
127-
String number = Util.canonicalizeNumber(context, recipients.getPrimaryRecipient().getNumber());
128-
129-
Optional<ContactTokenDetails> details = accountManager.getContact(number);
112+
TextSecureDirectory directory = TextSecureDirectory.getInstance(context);
113+
TextSecureAccountManager accountManager = TextSecureCommunicationFactory.createManager(context);
114+
String number = Util.canonicalizeNumber(context, recipients.getPrimaryRecipient().getNumber());
115+
Optional<ContactTokenDetails> details = accountManager.getContact(number);
130116

131117
if (details.isPresent()) {
132118
directory.setNumber(details.get(), true);
133-
ApplicationContext.getInstance(context).getJobManager().add(new DirectoryRefreshJob(context));
119+
120+
List<String> newUsers = updateContactsDatabase(context, localNumber, details.get());
121+
122+
if (!newUsers.isEmpty() && TextSecurePreferences.isMultiDevice(context)) {
123+
ApplicationContext.getInstance(context).getJobManager().add(new MultiDeviceContactUpdateJob(context));
124+
}
125+
126+
notifyNewUsers(context, masterSecret, newUsers);
127+
134128
return new UserCapabilities(Capability.SUPPORTED, details.get().isVoice() ? Capability.SUPPORTED : Capability.UNSUPPORTED);
135129
} else {
136130
ContactTokenDetails absent = new ContactTokenDetails();
@@ -185,6 +179,45 @@ public static UserCapabilities refreshDirectoryFor(Context context, Recipients r
185179
}
186180
}
187181

182+
private static @NonNull List<String> updateContactsDatabase(@NonNull Context context,
183+
@NonNull String localNumber,
184+
@NonNull final ContactTokenDetails activeToken)
185+
{
186+
return updateContactsDatabase(context, localNumber,
187+
new LinkedList<ContactTokenDetails>() {{add(activeToken);}},
188+
false);
189+
}
190+
191+
private static @NonNull List<String> updateContactsDatabase(@NonNull Context context,
192+
@NonNull String localNumber,
193+
@NonNull List<ContactTokenDetails> activeTokens,
194+
boolean removeMissing)
195+
{
196+
Optional<Account> account = getOrCreateAccount(context);
197+
198+
if (account.isPresent()) {
199+
try {
200+
return DatabaseFactory.getContactsDatabase(context)
201+
.setRegisteredUsers(account.get(), localNumber, activeTokens, removeMissing);
202+
} catch (RemoteException | OperationApplicationException e) {
203+
Log.w(TAG, e);
204+
}
205+
}
206+
207+
return new LinkedList<>();
208+
}
209+
210+
private static void notifyNewUsers(@NonNull Context context,
211+
@Nullable MasterSecret masterSecret,
212+
@NonNull List<String> newUsers)
213+
{
214+
for (String newUser : newUsers) {
215+
IncomingJoinedMessage message = new IncomingJoinedMessage(newUser);
216+
Pair<Long, Long> smsAndThreadId = DatabaseFactory.getSmsDatabase(context).insertMessageInbox(message);
217+
MessageNotifier.updateNotification(context, masterSecret, smsAndThreadId.second);
218+
}
219+
}
220+
188221
private static Optional<Account> getOrCreateAccount(Context context) {
189222
AccountManager accountManager = AccountManager.get(context);
190223
Account[] accounts = accountManager.getAccountsByType("org.thoughtcrime.securesms");

0 commit comments

Comments
 (0)