use of org.thoughtcrime.securesms.database.RecipientDatabase in project Signal-Android by signalapp.
the class NotificationChannels method restoreContactNotificationChannels.
/**
* Recreates all notification channels for contacts with custom notifications enabled. Should be
* safe to call repeatedly. Needs to be executed on a background thread.
*/
@WorkerThread
public static synchronized void restoreContactNotificationChannels(@NonNull Context context) {
if (!NotificationChannels.supported()) {
return;
}
RecipientDatabase db = SignalDatabase.recipients();
try (RecipientDatabase.RecipientReader reader = db.getRecipientsWithNotificationChannels()) {
Recipient recipient;
while ((recipient = reader.getNext()) != null) {
NotificationManager notificationManager = ServiceUtil.getNotificationManager(context);
if (!channelExists(notificationManager.getNotificationChannel(recipient.getNotificationChannel()))) {
String id = createChannelFor(context, recipient);
db.setNotificationChannel(recipient.getId(), id);
}
}
}
ensureCustomChannelConsistency(context);
}
use of org.thoughtcrime.securesms.database.RecipientDatabase in project Signal-Android by signalapp.
the class DirectoryHelper method syncRecipientInfoWithSystemContacts.
private static void syncRecipientInfoWithSystemContacts(@NonNull Context context, @NonNull Map<String, String> rewrites) {
RecipientDatabase recipientDatabase = SignalDatabase.recipients();
BulkOperationsHandle handle = recipientDatabase.beginBulkSystemContactUpdate();
try (Cursor cursor = ContactAccessor.getInstance().getAllSystemContacts(context)) {
while (cursor != null && cursor.moveToNext()) {
String mimeType = getMimeType(cursor);
if (!isPhoneMimeType(mimeType)) {
continue;
}
String lookupKey = getLookupKey(cursor);
ContactHolder contactHolder = new ContactHolder(lookupKey);
while (!cursor.isAfterLast() && getLookupKey(cursor).equals(lookupKey) && isPhoneMimeType(getMimeType(cursor))) {
String number = CursorUtil.requireString(cursor, ContactsContract.CommonDataKinds.Phone.NUMBER);
if (isValidContactNumber(number)) {
String formattedNumber = PhoneNumberFormatter.get(context).format(number);
String realNumber = Util.getFirstNonEmpty(rewrites.get(formattedNumber), formattedNumber);
PhoneNumberRecord.Builder builder = new PhoneNumberRecord.Builder();
builder.withRecipientId(Recipient.externalContact(context, realNumber).getId());
builder.withDisplayName(CursorUtil.requireString(cursor, ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
builder.withContactPhotoUri(CursorUtil.requireString(cursor, ContactsContract.CommonDataKinds.Phone.PHOTO_URI));
builder.withContactLabel(CursorUtil.requireString(cursor, ContactsContract.CommonDataKinds.Phone.LABEL));
builder.withPhoneType(CursorUtil.requireInt(cursor, ContactsContract.CommonDataKinds.Phone.TYPE));
builder.withContactUri(ContactsContract.Contacts.getLookupUri(CursorUtil.requireLong(cursor, ContactsContract.CommonDataKinds.Phone._ID), CursorUtil.requireString(cursor, ContactsContract.CommonDataKinds.Phone.LOOKUP_KEY)));
contactHolder.addPhoneNumberRecord(builder.build());
} else {
Log.w(TAG, "Skipping phone entry with invalid number");
}
cursor.moveToNext();
}
if (!cursor.isAfterLast() && getLookupKey(cursor).equals(lookupKey)) {
if (isStructuredNameMimeType(getMimeType(cursor))) {
StructuredNameRecord.Builder builder = new StructuredNameRecord.Builder();
builder.withGivenName(CursorUtil.requireString(cursor, ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME));
builder.withFamilyName(CursorUtil.requireString(cursor, ContactsContract.CommonDataKinds.StructuredName.FAMILY_NAME));
contactHolder.setStructuredNameRecord(builder.build());
} else {
Log.i(TAG, "Skipping invalid mimeType " + mimeType);
}
} else {
Log.i(TAG, "No structured name for user, rolling back cursor.");
cursor.moveToPrevious();
}
contactHolder.commit(handle);
}
} catch (IllegalStateException e) {
Log.w(TAG, "Hit an issue with the cursor while reading!", e);
} finally {
handle.finish();
}
if (NotificationChannels.supported()) {
try (RecipientDatabase.RecipientReader recipients = SignalDatabase.recipients().getRecipientsWithNotificationChannels()) {
Recipient recipient;
while ((recipient = recipients.getNext()) != null) {
NotificationChannels.updateContactChannelName(context, recipient);
}
}
}
}
use of org.thoughtcrime.securesms.database.RecipientDatabase in project Signal-Android by signalapp.
the class InsightsRepository method getInsecureRecipients.
@Override
public void getInsecureRecipients(@NonNull Consumer<List<Recipient>> insecureRecipientsConsumer) {
SimpleTask.run(() -> {
RecipientDatabase recipientDatabase = SignalDatabase.recipients();
List<RecipientId> unregisteredRecipients = recipientDatabase.getUninvitedRecipientsForInsights();
return Stream.of(unregisteredRecipients).map(Recipient::resolved).toList();
}, insecureRecipientsConsumer::accept);
}
use of org.thoughtcrime.securesms.database.RecipientDatabase in project Signal-Android by signalapp.
the class InviteReminderRepository method setHasSeenFirstInviteReminder.
@Override
public void setHasSeenFirstInviteReminder(Recipient recipient) {
RecipientDatabase recipientDatabase = SignalDatabase.recipients();
recipientDatabase.setSeenFirstInviteReminder(recipient.getId());
}
use of org.thoughtcrime.securesms.database.RecipientDatabase in project Signal-Android by signalapp.
the class RetrieveProfileJob method onRun.
@Override
public void onRun() throws IOException, RetryLaterException {
if (!SignalStore.account().isRegistered()) {
Log.w(TAG, "Unregistered. Skipping.");
return;
}
Stopwatch stopwatch = new Stopwatch("RetrieveProfile");
RecipientDatabase recipientDatabase = SignalDatabase.recipients();
RecipientUtil.ensureUuidsAreAvailable(context, Stream.of(Recipient.resolvedList(recipientIds)).filter(r -> r.getRegistered() != RecipientDatabase.RegisteredState.NOT_REGISTERED).toList());
List<Recipient> recipients = Recipient.resolvedList(recipientIds);
stopwatch.split("resolve-ensure");
ProfileService profileService = new ProfileService(ApplicationDependencies.getGroupsV2Operations().getProfileOperations(), ApplicationDependencies.getSignalServiceMessageReceiver(), ApplicationDependencies.getSignalWebSocket());
List<Observable<Pair<Recipient, ServiceResponse<ProfileAndCredential>>>> requests = Stream.of(recipients).filter(Recipient::hasServiceId).map(r -> ProfileUtil.retrieveProfile(context, r, getRequestType(r), profileService).toObservable()).toList();
stopwatch.split("requests");
OperationState operationState = Observable.mergeDelayError(requests).observeOn(Schedulers.io(), true).scan(new OperationState(), (state, pair) -> {
Recipient recipient = pair.first();
ProfileService.ProfileResponseProcessor processor = new ProfileService.ProfileResponseProcessor(pair.second());
if (processor.hasResult()) {
state.profiles.add(processor.getResult(recipient));
} else if (processor.notFound()) {
Log.w(TAG, "Failed to find a profile for " + recipient.getId());
if (recipient.isRegistered()) {
state.unregistered.add(recipient.getId());
}
} else if (processor.genericIoError()) {
state.retries.add(recipient.getId());
} else {
Log.w(TAG, "Failed to retrieve profile for " + recipient.getId());
}
return state;
}).lastOrError().blockingGet();
stopwatch.split("responses");
Set<RecipientId> success = SetUtil.difference(recipientIds, operationState.retries);
Map<RecipientId, ServiceId> newlyRegistered = Stream.of(operationState.profiles).map(Pair::first).filterNot(Recipient::isRegistered).collect(Collectors.toMap(Recipient::getId, r -> r.getServiceId().orNull()));
// noinspection SimplifyStreamApiCallChains
Util.chunk(operationState.profiles, 150).stream().forEach(list -> {
SignalDatabase.runInTransaction(() -> {
for (Pair<Recipient, ProfileAndCredential> profile : list) {
process(profile.first(), profile.second());
}
});
});
recipientDatabase.markProfilesFetched(success, System.currentTimeMillis());
if (operationState.unregistered.size() > 0 || newlyRegistered.size() > 0) {
Log.i(TAG, "Marking " + newlyRegistered.size() + " users as registered and " + operationState.unregistered.size() + " users as unregistered.");
recipientDatabase.bulkUpdatedRegisteredStatus(newlyRegistered, operationState.unregistered);
}
stopwatch.split("process");
for (Pair<Recipient, ProfileAndCredential> profile : operationState.profiles) {
setIdentityKey(profile.first(), profile.second().getProfile().getIdentityKey());
}
stopwatch.split("identityKeys");
long keyCount = Stream.of(operationState.profiles).map(Pair::first).map(Recipient::getProfileKey).withoutNulls().count();
Log.d(TAG, String.format(Locale.US, "Started with %d recipient(s). Found %d profile(s), and had keys for %d of them. Will retry %d.", recipients.size(), operationState.profiles.size(), keyCount, operationState.retries.size()));
stopwatch.stop(TAG);
recipientIds.clear();
recipientIds.addAll(operationState.retries);
if (recipientIds.size() > 0) {
throw new RetryLaterException();
}
}
Aggregations