Do registration checks for new numbers during group creation.
This commit is contained in:
parent
cb81a9f783
commit
70e33518a9
3 changed files with 145 additions and 34 deletions
|
@ -3,7 +3,12 @@ package org.thoughtcrime.securesms.groups;
|
|||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.WorkerThread;
|
||||
|
||||
import com.annimon.stream.Collectors;
|
||||
import com.annimon.stream.Stream;
|
||||
|
||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||
import org.thoughtcrime.securesms.jobmanager.Job;
|
||||
import org.thoughtcrime.securesms.jobmanager.JobManager;
|
||||
import org.thoughtcrime.securesms.jobs.RetrieveProfileJob;
|
||||
import org.thoughtcrime.securesms.logging.Log;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
|
@ -12,15 +17,39 @@ import org.thoughtcrime.securesms.recipients.RecipientId;
|
|||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public final class GroupsV2CapabilityChecker {
|
||||
|
||||
private static final String TAG = Log.tag(GroupsV2CapabilityChecker.class);
|
||||
|
||||
GroupsV2CapabilityChecker() {}
|
||||
public GroupsV2CapabilityChecker() {}
|
||||
|
||||
/**
|
||||
* @param resolved A collection of resolved recipients.
|
||||
*/
|
||||
@WorkerThread
|
||||
public void refreshCapabilitiesIfNecessary(@NonNull Collection<Recipient> resolved) throws IOException {
|
||||
List<RecipientId> needsRefresh = Stream.of(resolved)
|
||||
.filter(r -> r.getGroupsV2Capability() != Recipient.Capability.SUPPORTED)
|
||||
.map(Recipient::getId)
|
||||
.toList();
|
||||
|
||||
if (needsRefresh.size() > 0) {
|
||||
Log.d(TAG, "[refreshCapabilitiesIfNecessary] Need to refresh " + needsRefresh.size() + " recipients.");
|
||||
|
||||
List<Job> jobs = RetrieveProfileJob.forRecipients(needsRefresh);
|
||||
JobManager jobManager = ApplicationDependencies.getJobManager();
|
||||
|
||||
for (Job job : jobs) {
|
||||
if (!jobManager.runSynchronously(job, TimeUnit.SECONDS.toMillis(5000)).isPresent()) {
|
||||
throw new IOException("Recipient capability was not retrieved in time");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
boolean allAndSelfSupportGroupsV2AndUuid(@NonNull Collection<RecipientId> recipientIds)
|
||||
|
@ -37,25 +66,16 @@ public final class GroupsV2CapabilityChecker {
|
|||
boolean allSupportGroupsV2AndUuid(@NonNull Collection<RecipientId> recipientIds)
|
||||
throws IOException
|
||||
{
|
||||
final HashSet<RecipientId> recipientIdsSet = new HashSet<>(recipientIds);
|
||||
Set<RecipientId> recipientIdsSet = new HashSet<>(recipientIds);
|
||||
Set<Recipient> resolved = Stream.of(recipientIdsSet).map(Recipient::resolved).collect(Collectors.toSet());
|
||||
|
||||
for (RecipientId recipientId : recipientIdsSet) {
|
||||
Recipient member = Recipient.resolved(recipientId);
|
||||
Recipient.Capability gv2Capability = member.getGroupsV2Capability();
|
||||
|
||||
if (gv2Capability != Recipient.Capability.SUPPORTED) {
|
||||
if (!ApplicationDependencies.getJobManager().runSynchronously(RetrieveProfileJob.forRecipient(member.getId()), TimeUnit.SECONDS.toMillis(1000)).isPresent()) {
|
||||
throw new IOException("Recipient capability was not retrieved in time");
|
||||
}
|
||||
}
|
||||
}
|
||||
refreshCapabilitiesIfNecessary(resolved);
|
||||
|
||||
boolean noSelfGV2Support = false;
|
||||
int noGv2Count = 0;
|
||||
int noUuidCount = 0;
|
||||
|
||||
for (RecipientId recipientId : recipientIdsSet) {
|
||||
Recipient member = Recipient.resolved(recipientId);
|
||||
for (Recipient member : resolved) {
|
||||
Recipient.Capability gv2Capability = member.getGroupsV2Capability();
|
||||
|
||||
if (gv2Capability != Recipient.Capability.SUPPORTED) {
|
||||
|
|
|
@ -8,6 +8,7 @@ import android.view.View;
|
|||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
|
||||
import com.annimon.stream.Stream;
|
||||
|
||||
|
@ -15,14 +16,37 @@ import org.thoughtcrime.securesms.ContactSelectionActivity;
|
|||
import org.thoughtcrime.securesms.ContactSelectionListFragment;
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.contacts.ContactsCursorLoader;
|
||||
import org.thoughtcrime.securesms.contacts.sync.DirectoryHelper;
|
||||
import org.thoughtcrime.securesms.database.RecipientDatabase;
|
||||
import org.thoughtcrime.securesms.groups.GroupsV2CapabilityChecker;
|
||||
import org.thoughtcrime.securesms.groups.ui.creategroup.details.AddGroupDetailsActivity;
|
||||
import org.thoughtcrime.securesms.logging.Log;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||
import org.thoughtcrime.securesms.util.FeatureFlags;
|
||||
import org.thoughtcrime.securesms.util.ProfileUtil;
|
||||
import org.thoughtcrime.securesms.util.Stopwatch;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
import org.thoughtcrime.securesms.util.concurrent.SimpleTask;
|
||||
import org.thoughtcrime.securesms.util.views.SimpleProgressDialog;
|
||||
import org.whispersystems.libsignal.util.guava.Optional;
|
||||
import org.whispersystems.signalservice.api.profiles.ProfileAndCredential;
|
||||
import org.whispersystems.signalservice.api.profiles.SignalServiceProfile;
|
||||
import org.whispersystems.signalservice.internal.util.concurrent.ListenableFuture;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
public class CreateGroupActivity extends ContactSelectionActivity {
|
||||
|
||||
private static String TAG = Log.tag(CreateGroupActivity.class);
|
||||
|
||||
private static final int MINIMUM_GROUP_SIZE = 1;
|
||||
private static final short REQUEST_CODE_ADD_DETAILS = 17275;
|
||||
|
||||
|
@ -109,10 +133,63 @@ public class CreateGroupActivity extends ContactSelectionActivity {
|
|||
}
|
||||
|
||||
private void handleNextPressed() {
|
||||
Stopwatch stopwatch = new Stopwatch("Recipient Refresh");
|
||||
AtomicReference<AlertDialog> progressDialog = new AtomicReference<>();
|
||||
|
||||
Runnable showDialogRunnable = () -> {
|
||||
Log.i(TAG, "Taking some time. Showing a progress dialog.");
|
||||
progressDialog.set(SimpleProgressDialog.show(this));
|
||||
};
|
||||
|
||||
next.postDelayed(showDialogRunnable, 300);
|
||||
|
||||
SimpleTask.run(getLifecycle(), () -> {
|
||||
RecipientId[] ids = Stream.of(contactsFragment.getSelectedContacts())
|
||||
.map(selectedContact -> selectedContact.getOrCreateRecipientId(this))
|
||||
.toArray(RecipientId[]::new);
|
||||
|
||||
List<Recipient> resolved = Stream.of(ids)
|
||||
.map(Recipient::resolved)
|
||||
.toList();
|
||||
|
||||
stopwatch.split("resolve");
|
||||
|
||||
List<Recipient> registeredChecks = Stream.of(resolved)
|
||||
.filter(r -> r.getRegistered() == RecipientDatabase.RegisteredState.UNKNOWN)
|
||||
.toList();
|
||||
|
||||
Log.i(TAG, "Need to do " + registeredChecks.size() + " registration checks.");
|
||||
|
||||
for (Recipient recipient : registeredChecks) {
|
||||
try {
|
||||
DirectoryHelper.refreshDirectoryFor(this, recipient, false);
|
||||
} catch (IOException e) {
|
||||
Log.w(TAG, "Failed to refresh registered status for " + recipient.getId(), e);
|
||||
}
|
||||
}
|
||||
|
||||
stopwatch.split("registered");
|
||||
|
||||
if (FeatureFlags.groupsV2()) {
|
||||
try {
|
||||
new GroupsV2CapabilityChecker().refreshCapabilitiesIfNecessary(resolved);
|
||||
} catch (IOException e) {
|
||||
Log.w(TAG, "Failed to refresh all recipient capabilities.", e);
|
||||
}
|
||||
}
|
||||
|
||||
stopwatch.split("capabilities");
|
||||
|
||||
return ids;
|
||||
}, ids -> {
|
||||
if (progressDialog.get() != null) {
|
||||
progressDialog.get().dismiss();
|
||||
}
|
||||
|
||||
next.removeCallbacks(showDialogRunnable);
|
||||
stopwatch.stop(TAG);
|
||||
|
||||
startActivityForResult(AddGroupDetailsActivity.newIntent(this, ids), REQUEST_CODE_ADD_DETAILS);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -101,26 +101,13 @@ public class RetrieveProfileJob extends BaseJob {
|
|||
*/
|
||||
@WorkerThread
|
||||
public static void enqueue(@NonNull Collection<RecipientId> recipientIds) {
|
||||
Context context = ApplicationDependencies.getApplication();
|
||||
JobManager jobManager = ApplicationDependencies.getJobManager();
|
||||
List<RecipientId> combined = new LinkedList<>();
|
||||
|
||||
for (RecipientId recipientId : recipientIds) {
|
||||
Recipient recipient = Recipient.resolved(recipientId);
|
||||
|
||||
if (recipient.isLocalNumber()) {
|
||||
jobManager.add(new RefreshOwnProfileJob());
|
||||
} else if (recipient.isGroup()) {
|
||||
List<Recipient> recipients = DatabaseFactory.getGroupDatabase(context).getGroupMembers(recipient.requireGroupId(), GroupDatabase.MemberSet.FULL_MEMBERS_EXCLUDING_SELF);
|
||||
combined.addAll(Stream.of(recipients).map(Recipient::getId).toList());
|
||||
} else {
|
||||
combined.add(recipientId);
|
||||
for (Job job : forRecipients(recipientIds)) {
|
||||
jobManager.add(job);
|
||||
}
|
||||
}
|
||||
|
||||
jobManager.add(new RetrieveProfileJob(combined));
|
||||
}
|
||||
|
||||
/**
|
||||
* Works for any RecipientId, whether it's an individual, group, or yourself.
|
||||
*/
|
||||
|
@ -140,6 +127,33 @@ public class RetrieveProfileJob extends BaseJob {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Works for any RecipientId, whether it's an individual, group, or yourself.
|
||||
*/
|
||||
@WorkerThread
|
||||
public static @NonNull List<Job> forRecipients(@NonNull Collection<RecipientId> recipientIds) {
|
||||
Context context = ApplicationDependencies.getApplication();
|
||||
List<RecipientId> combined = new LinkedList<>();
|
||||
List<Job> jobs = new LinkedList<>();
|
||||
|
||||
for (RecipientId recipientId : recipientIds) {
|
||||
Recipient recipient = Recipient.resolved(recipientId);
|
||||
|
||||
if (recipient.isLocalNumber()) {
|
||||
jobs.add(new RefreshOwnProfileJob());
|
||||
} else if (recipient.isGroup()) {
|
||||
List<Recipient> recipients = DatabaseFactory.getGroupDatabase(context).getGroupMembers(recipient.requireGroupId(), GroupDatabase.MemberSet.FULL_MEMBERS_EXCLUDING_SELF);
|
||||
combined.addAll(Stream.of(recipients).map(Recipient::getId).toList());
|
||||
} else {
|
||||
combined.add(recipientId);
|
||||
}
|
||||
}
|
||||
|
||||
jobs.add(new RetrieveProfileJob(combined));
|
||||
|
||||
return jobs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Will fetch some profiles to ensure we're decently up-to-date if we haven't done so within a
|
||||
* certain time period.
|
||||
|
|
Loading…
Add table
Reference in a new issue