Search in sources :

Example 6 with Stopwatch

use of org.thoughtcrime.securesms.util.Stopwatch in project Signal-Android by signalapp.

the class CreateGroupActivity method handleNextPressed.

private void handleNextPressed() {
    Stopwatch stopwatch = new Stopwatch("Recipient Refresh");
    SimpleProgressDialog.DismissibleDialog dismissibleDialog = SimpleProgressDialog.showDelayed(this);
    SimpleTask.run(getLifecycle(), () -> {
        List<RecipientId> ids = contactsFragment.getSelectedContacts().stream().map(selectedContact -> selectedContact.getOrCreateRecipientId(this)).collect(Collectors.toList());
        List<Recipient> resolved = Recipient.resolvedList(ids);
        stopwatch.split("resolve");
        Set<Recipient> registeredChecks = resolved.stream().filter(r -> r.getRegistered() == RecipientDatabase.RegisteredState.UNKNOWN).collect(Collectors.toSet());
        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);
            }
        }
        if (registeredChecks.size() > 0) {
            resolved = Recipient.resolvedList(ids);
        }
        stopwatch.split("registered");
        List<Recipient> recipientsAndSelf = new ArrayList<>(resolved);
        recipientsAndSelf.add(Recipient.self().resolve());
        boolean neededRefresh = false;
        if (!SignalStore.internalValues().gv2DoNotCreateGv2Groups()) {
            try {
                neededRefresh = GroupsV2CapabilityChecker.refreshCapabilitiesIfNecessary(recipientsAndSelf);
            } catch (IOException e) {
                Log.w(TAG, "Failed to refresh all recipient capabilities.", e);
            }
        }
        if (neededRefresh) {
            resolved = Recipient.resolvedList(ids);
        }
        stopwatch.split("capabilities");
        Pair<Boolean, List<RecipientId>> result;
        boolean gv2 = Stream.of(recipientsAndSelf).allMatch(r -> r.getGroupsV2Capability() == Recipient.Capability.SUPPORTED);
        if (!gv2 && Stream.of(resolved).anyMatch(r -> !r.hasE164())) {
            Log.w(TAG, "Invalid GV1 group...");
            ids = Collections.emptyList();
            result = Pair.create(false, ids);
        } else {
            result = Pair.create(true, ids);
        }
        stopwatch.split("gv1-check");
        return result;
    }, result -> {
        dismissibleDialog.dismiss();
        stopwatch.stop(TAG);
        if (result.first) {
            startActivityForResult(AddGroupDetailsActivity.newIntent(this, result.second), REQUEST_CODE_ADD_DETAILS);
        } else {
            new AlertDialog.Builder(this).setMessage(R.string.CreateGroupActivity_some_contacts_cannot_be_in_legacy_groups).setPositiveButton(android.R.string.ok, (d, w) -> d.dismiss()).show();
        }
    });
}
Also used : SignalStore(org.thoughtcrime.securesms.keyvalue.SignalStore) Context(android.content.Context) Bundle(android.os.Bundle) AlertDialog(androidx.appcompat.app.AlertDialog) Stream(com.annimon.stream.Stream) ContactsCursorLoader(org.thoughtcrime.securesms.contacts.ContactsCursorLoader) DirectoryHelper(org.thoughtcrime.securesms.contacts.sync.DirectoryHelper) Util(org.thoughtcrime.securesms.util.Util) NonNull(androidx.annotation.NonNull) ContactSelectionListFragment(org.thoughtcrime.securesms.ContactSelectionListFragment) SimpleProgressDialog(org.thoughtcrime.securesms.util.views.SimpleProgressDialog) Pair(android.util.Pair) Intent(android.content.Intent) ViewUtil(org.thoughtcrime.securesms.util.ViewUtil) R(org.thoughtcrime.securesms.R) RecipientDatabase(org.thoughtcrime.securesms.database.RecipientDatabase) MenuItem(android.view.MenuItem) ArrayList(java.util.ArrayList) RecipientId(org.thoughtcrime.securesms.recipients.RecipientId) MaterialButton(com.google.android.material.button.MaterialButton) Recipient(org.thoughtcrime.securesms.recipients.Recipient) GroupsV2CapabilityChecker(org.thoughtcrime.securesms.groups.GroupsV2CapabilityChecker) ExtendedFloatingActionButton(com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton) SimpleTask(org.thoughtcrime.securesms.util.concurrent.SimpleTask) ContactSelectionActivity(org.thoughtcrime.securesms.ContactSelectionActivity) Set(java.util.Set) IOException(java.io.IOException) Collectors(java.util.stream.Collectors) AddGroupDetailsActivity(org.thoughtcrime.securesms.groups.ui.creategroup.details.AddGroupDetailsActivity) Optional(org.whispersystems.libsignal.util.guava.Optional) Consumer(java.util.function.Consumer) Log(org.signal.core.util.logging.Log) FeatureFlags(org.thoughtcrime.securesms.util.FeatureFlags) List(java.util.List) Nullable(androidx.annotation.Nullable) Stopwatch(org.thoughtcrime.securesms.util.Stopwatch) Collections(java.util.Collections) ValueAnimator(android.animation.ValueAnimator) AlertDialog(androidx.appcompat.app.AlertDialog) RecipientId(org.thoughtcrime.securesms.recipients.RecipientId) Stopwatch(org.thoughtcrime.securesms.util.Stopwatch) ArrayList(java.util.ArrayList) Recipient(org.thoughtcrime.securesms.recipients.Recipient) IOException(java.io.IOException) ArrayList(java.util.ArrayList) List(java.util.List) SimpleProgressDialog(org.thoughtcrime.securesms.util.views.SimpleProgressDialog)

Example 7 with Stopwatch

use of org.thoughtcrime.securesms.util.Stopwatch in project Signal-Android by signalapp.

the class QrCode method create.

@NonNull
public static Bitmap create(@Nullable String data, @ColorInt int foregroundColor, @ColorInt int backgroundColor) {
    if (data == null || data.length() == 0) {
        Log.w(TAG, "No data");
        return Bitmap.createBitmap(512, 512, Bitmap.Config.ARGB_8888);
    }
    try {
        Stopwatch stopwatch = new Stopwatch("QrGen");
        QRCodeWriter qrCodeWriter = new QRCodeWriter();
        BitMatrix qrData = qrCodeWriter.encode(data, BarcodeFormat.QR_CODE, 512, 512);
        int qrWidth = qrData.getWidth();
        int qrHeight = qrData.getHeight();
        int[] pixels = new int[qrWidth * qrHeight];
        for (int y = 0; y < qrHeight; y++) {
            int offset = y * qrWidth;
            for (int x = 0; x < qrWidth; x++) {
                pixels[offset + x] = qrData.get(x, y) ? foregroundColor : backgroundColor;
            }
        }
        stopwatch.split("Write pixels");
        Bitmap bitmap = Bitmap.createBitmap(pixels, qrWidth, qrHeight, Bitmap.Config.ARGB_8888);
        stopwatch.split("Create bitmap");
        stopwatch.stop(TAG);
        return bitmap;
    } catch (WriterException e) {
        Log.w(TAG, e);
        return Bitmap.createBitmap(512, 512, Bitmap.Config.ARGB_8888);
    }
}
Also used : QRCodeWriter(com.google.zxing.qrcode.QRCodeWriter) Bitmap(android.graphics.Bitmap) Stopwatch(org.thoughtcrime.securesms.util.Stopwatch) BitMatrix(com.google.zxing.common.BitMatrix) WriterException(com.google.zxing.WriterException) NonNull(androidx.annotation.NonNull)

Example 8 with Stopwatch

use of org.thoughtcrime.securesms.util.Stopwatch in project Signal-Android by signalapp.

the class CameraXFragment method onCaptureClicked.

private void onCaptureClicked() {
    Stopwatch stopwatch = new Stopwatch("Capture");
    CameraXSelfieFlashHelper flashHelper = new CameraXSelfieFlashHelper(requireActivity().getWindow(), camera, selfieFlash);
    camera.takePicture(Executors.mainThreadExecutor(), new ImageCapture.OnImageCapturedCallback() {

        @Override
        public void onCaptureSuccess(@NonNull ImageProxy image) {
            flashHelper.endFlash();
            SimpleTask.run(CameraXFragment.this.getViewLifecycleOwner().getLifecycle(), () -> {
                stopwatch.split("captured");
                try {
                    return CameraXUtil.toJpeg(image, camera.getCameraLensFacing() == CameraSelector.LENS_FACING_FRONT);
                } catch (IOException e) {
                    Log.w(TAG, "Failed to encode captured image.", e);
                    return null;
                } finally {
                    image.close();
                }
            }, result -> {
                stopwatch.split("transformed");
                stopwatch.stop(TAG);
                if (result != null) {
                    controller.onImageCaptured(result.getData(), result.getWidth(), result.getHeight());
                } else {
                    controller.onCameraError();
                }
            });
        }

        @Override
        public void onError(ImageCaptureException exception) {
            Log.w(TAG, "Failed to capture image", exception);
            flashHelper.endFlash();
            controller.onCameraError();
        }
    });
    flashHelper.startFlash();
}
Also used : RequiresApi(androidx.annotation.RequiresApi) Bundle(android.os.Bundle) NonNull(androidx.annotation.NonNull) WindowManager(android.view.WindowManager) ImageView(android.widget.ImageView) Animator(android.animation.Animator) R(org.thoughtcrime.securesms.R) ProcessCameraProvider(androidx.camera.lifecycle.ProcessCameraProvider) VideoUtil(org.thoughtcrime.securesms.video.VideoUtil) View(android.view.View) Animation(android.view.animation.Animation) ContextCompat(androidx.core.content.ContextCompat) Executors(com.bumptech.glide.util.Executors) ImageProxy(androidx.camera.core.ImageProxy) Surface(android.view.Surface) ImageCapture(androidx.camera.core.ImageCapture) ViewGroup(android.view.ViewGroup) MediaCountIndicatorButton(org.thoughtcrime.securesms.mediasend.v2.MediaCountIndicatorButton) Log(org.signal.core.util.logging.Log) Nullable(androidx.annotation.Nullable) AnimationCompleteListener(org.thoughtcrime.securesms.animation.AnimationCompleteListener) DecelerateInterpolator(android.view.animation.DecelerateInterpolator) Context(android.content.Context) GestureDetector(android.view.GestureDetector) PreviewView(androidx.camera.view.PreviewView) CameraXUtil(org.thoughtcrime.securesms.mediasend.camerax.CameraXUtil) CameraSelector(androidx.camera.core.CameraSelector) AnimationUtils(android.view.animation.AnimationUtils) TextSecurePreferences(org.thoughtcrime.securesms.util.TextSecurePreferences) TooltipPopup(org.thoughtcrime.securesms.components.TooltipPopup) SuppressLint(android.annotation.SuppressLint) MotionEvent(android.view.MotionEvent) Toast(android.widget.Toast) ImageCaptureException(androidx.camera.core.ImageCaptureException) MemoryFileDescriptor(org.thoughtcrime.securesms.util.MemoryFileDescriptor) Build(android.os.Build) CameraXFlashToggleView(org.thoughtcrime.securesms.mediasend.camerax.CameraXFlashToggleView) SimpleTask(org.thoughtcrime.securesms.util.concurrent.SimpleTask) LayoutInflater(android.view.LayoutInflater) MediaAnimations(org.thoughtcrime.securesms.mediasend.v2.MediaAnimations) IOException(java.io.IOException) SignalCameraView(androidx.camera.view.SignalCameraView) RotateAnimation(android.view.animation.RotateAnimation) Optional(org.whispersystems.libsignal.util.guava.Optional) Glide(com.bumptech.glide.Glide) MediaConstraints(org.thoughtcrime.securesms.mms.MediaConstraints) Configuration(android.content.res.Configuration) DecryptableUri(org.thoughtcrime.securesms.mms.DecryptableStreamUriLoader.DecryptableUri) Stopwatch(org.thoughtcrime.securesms.util.Stopwatch) FileDescriptor(java.io.FileDescriptor) LoggingFragment(org.thoughtcrime.securesms.LoggingFragment) ImageCaptureException(androidx.camera.core.ImageCaptureException) Stopwatch(org.thoughtcrime.securesms.util.Stopwatch) ImageCapture(androidx.camera.core.ImageCapture) IOException(java.io.IOException) ImageProxy(androidx.camera.core.ImageProxy)

Example 9 with Stopwatch

use of org.thoughtcrime.securesms.util.Stopwatch in project Signal-Android by signalapp.

the class StorageSyncJob method performSync.

private boolean performSync() throws IOException, RetryLaterException, InvalidKeyException {
    final Stopwatch stopwatch = new Stopwatch("StorageSync");
    final SQLiteDatabase db = SignalDatabase.getRawDatabase();
    final SignalServiceAccountManager accountManager = ApplicationDependencies.getSignalServiceAccountManager();
    final UnknownStorageIdDatabase storageIdDatabase = SignalDatabase.unknownStorageIds();
    final StorageKey storageServiceKey = SignalStore.storageService().getOrCreateStorageKey();
    final SignalStorageManifest localManifest = SignalStore.storageService().getManifest();
    final SignalStorageManifest remoteManifest = accountManager.getStorageManifestIfDifferentVersion(storageServiceKey, localManifest.getVersion()).or(localManifest);
    stopwatch.split("remote-manifest");
    Recipient self = freshSelf();
    boolean needsMultiDeviceSync = false;
    boolean needsForcePush = false;
    if (self.getStorageServiceId() == null) {
        Log.w(TAG, "No storageId for self. Generating.");
        SignalDatabase.recipients().updateStorageId(self.getId(), StorageSyncHelper.generateKey());
        self = freshSelf();
    }
    Log.i(TAG, "Our version: " + localManifest.getVersion() + ", their version: " + remoteManifest.getVersion());
    if (remoteManifest.getVersion() > localManifest.getVersion()) {
        Log.i(TAG, "[Remote Sync] Newer manifest version found!");
        List<StorageId> localStorageIdsBeforeMerge = getAllLocalStorageIds(context, self);
        IdDifferenceResult idDifference = StorageSyncHelper.findIdDifference(remoteManifest.getStorageIds(), localStorageIdsBeforeMerge);
        if (idDifference.hasTypeMismatches() && SignalStore.account().isPrimaryDevice()) {
            Log.w(TAG, "[Remote Sync] Found type mismatches in the ID sets! Scheduling a force push after this sync completes.");
            needsForcePush = true;
        }
        Log.i(TAG, "[Remote Sync] Pre-Merge ID Difference :: " + idDifference);
        stopwatch.split("remote-id-diff");
        if (!idDifference.isEmpty()) {
            Log.i(TAG, "[Remote Sync] Retrieving records for key difference.");
            List<SignalStorageRecord> remoteOnly = accountManager.readStorageRecords(storageServiceKey, idDifference.getRemoteOnlyIds());
            stopwatch.split("remote-records");
            if (remoteOnly.size() != idDifference.getRemoteOnlyIds().size()) {
                Log.w(TAG, "[Remote Sync] Could not find all remote-only records! Requested: " + idDifference.getRemoteOnlyIds().size() + ", Found: " + remoteOnly.size() + ". These stragglers should naturally get deleted during the sync.");
            }
            List<SignalContactRecord> remoteContacts = new LinkedList<>();
            List<SignalGroupV1Record> remoteGv1 = new LinkedList<>();
            List<SignalGroupV2Record> remoteGv2 = new LinkedList<>();
            List<SignalAccountRecord> remoteAccount = new LinkedList<>();
            List<SignalStorageRecord> remoteUnknown = new LinkedList<>();
            for (SignalStorageRecord remote : remoteOnly) {
                if (remote.getContact().isPresent()) {
                    remoteContacts.add(remote.getContact().get());
                } else if (remote.getGroupV1().isPresent()) {
                    remoteGv1.add(remote.getGroupV1().get());
                } else if (remote.getGroupV2().isPresent()) {
                    remoteGv2.add(remote.getGroupV2().get());
                } else if (remote.getAccount().isPresent()) {
                    remoteAccount.add(remote.getAccount().get());
                } else if (remote.getId().isUnknown()) {
                    remoteUnknown.add(remote);
                } else {
                    Log.w(TAG, "Bad record! Type is a known value (" + remote.getId().getType() + "), but doesn't have a matching inner record. Dropping it.");
                }
            }
            db.beginTransaction();
            try {
                self = freshSelf();
                Log.i(TAG, "[Remote Sync] Remote-Only :: Contacts: " + remoteContacts.size() + ", GV1: " + remoteGv1.size() + ", GV2: " + remoteGv2.size() + ", Account: " + remoteAccount.size());
                new ContactRecordProcessor(context, self).process(remoteContacts, StorageSyncHelper.KEY_GENERATOR);
                new GroupV1RecordProcessor(context).process(remoteGv1, StorageSyncHelper.KEY_GENERATOR);
                new GroupV2RecordProcessor(context).process(remoteGv2, StorageSyncHelper.KEY_GENERATOR);
                self = freshSelf();
                new AccountRecordProcessor(context, self).process(remoteAccount, StorageSyncHelper.KEY_GENERATOR);
                List<SignalStorageRecord> unknownInserts = remoteUnknown;
                List<StorageId> unknownDeletes = Stream.of(idDifference.getLocalOnlyIds()).filter(StorageId::isUnknown).toList();
                Log.i(TAG, "[Remote Sync] Unknowns :: " + unknownInserts.size() + " inserts, " + unknownDeletes.size() + " deletes");
                storageIdDatabase.insert(unknownInserts);
                storageIdDatabase.delete(unknownDeletes);
                db.setTransactionSuccessful();
            } finally {
                db.endTransaction();
                ApplicationDependencies.getDatabaseObserver().notifyConversationListListeners();
                stopwatch.split("remote-merge-transaction");
            }
        } else {
            Log.i(TAG, "[Remote Sync] Remote version was newer, but there were no remote-only IDs.");
        }
    } else if (remoteManifest.getVersion() < localManifest.getVersion()) {
        Log.w(TAG, "[Remote Sync] Remote version was older. User might have switched accounts.");
    }
    if (remoteManifest != localManifest) {
        Log.i(TAG, "[Remote Sync] Saved new manifest. Now at version: " + remoteManifest.getVersion());
        SignalStore.storageService().setManifest(remoteManifest);
    }
    Log.i(TAG, "We are up-to-date with the remote storage state.");
    final WriteOperationResult remoteWriteOperation;
    db.beginTransaction();
    try {
        self = freshSelf();
        List<StorageId> localStorageIds = getAllLocalStorageIds(context, self);
        IdDifferenceResult idDifference = StorageSyncHelper.findIdDifference(remoteManifest.getStorageIds(), localStorageIds);
        List<SignalStorageRecord> remoteInserts = buildLocalStorageRecords(context, self, idDifference.getLocalOnlyIds());
        List<byte[]> remoteDeletes = Stream.of(idDifference.getRemoteOnlyIds()).map(StorageId::getRaw).toList();
        Log.i(TAG, "ID Difference :: " + idDifference);
        remoteWriteOperation = new WriteOperationResult(new SignalStorageManifest(remoteManifest.getVersion() + 1, localStorageIds), remoteInserts, remoteDeletes);
        db.setTransactionSuccessful();
    } finally {
        db.endTransaction();
        stopwatch.split("local-data-transaction");
    }
    if (!remoteWriteOperation.isEmpty()) {
        Log.i(TAG, "We have something to write remotely.");
        Log.i(TAG, "WriteOperationResult :: " + remoteWriteOperation);
        StorageSyncValidations.validate(remoteWriteOperation, remoteManifest, needsForcePush, self);
        Optional<SignalStorageManifest> conflict = accountManager.writeStorageRecords(storageServiceKey, remoteWriteOperation.getManifest(), remoteWriteOperation.getInserts(), remoteWriteOperation.getDeletes());
        if (conflict.isPresent()) {
            Log.w(TAG, "Hit a conflict when trying to resolve the conflict! Retrying.");
            throw new RetryLaterException();
        }
        Log.i(TAG, "Saved new manifest. Now at version: " + remoteWriteOperation.getManifest().getVersion());
        SignalStore.storageService().setManifest(remoteWriteOperation.getManifest());
        stopwatch.split("remote-write");
        needsMultiDeviceSync = true;
    } else {
        Log.i(TAG, "No remote writes needed. Still at version: " + remoteManifest.getVersion());
    }
    if (needsForcePush && SignalStore.account().isPrimaryDevice()) {
        Log.w(TAG, "Scheduling a force push.");
        ApplicationDependencies.getJobManager().add(new StorageForcePushJob());
    }
    stopwatch.stop(TAG);
    return needsMultiDeviceSync;
}
Also used : SignalContactRecord(org.whispersystems.signalservice.api.storage.SignalContactRecord) Stopwatch(org.thoughtcrime.securesms.util.Stopwatch) StorageId(org.whispersystems.signalservice.api.storage.StorageId) GroupV2RecordProcessor(org.thoughtcrime.securesms.storage.GroupV2RecordProcessor) SignalGroupV2Record(org.whispersystems.signalservice.api.storage.SignalGroupV2Record) UnknownStorageIdDatabase(org.thoughtcrime.securesms.database.UnknownStorageIdDatabase) StorageKey(org.whispersystems.signalservice.api.storage.StorageKey) SignalAccountRecord(org.whispersystems.signalservice.api.storage.SignalAccountRecord) SignalStorageManifest(org.whispersystems.signalservice.api.storage.SignalStorageManifest) IdDifferenceResult(org.thoughtcrime.securesms.storage.StorageSyncHelper.IdDifferenceResult) GroupV1RecordProcessor(org.thoughtcrime.securesms.storage.GroupV1RecordProcessor) SignalServiceAccountManager(org.whispersystems.signalservice.api.SignalServiceAccountManager) SignalStorageRecord(org.whispersystems.signalservice.api.storage.SignalStorageRecord) Recipient(org.thoughtcrime.securesms.recipients.Recipient) WriteOperationResult(org.thoughtcrime.securesms.storage.StorageSyncHelper.WriteOperationResult) LinkedList(java.util.LinkedList) SignalGroupV1Record(org.whispersystems.signalservice.api.storage.SignalGroupV1Record) AccountRecordProcessor(org.thoughtcrime.securesms.storage.AccountRecordProcessor) SQLiteDatabase(net.zetetic.database.sqlcipher.SQLiteDatabase) ContactRecordProcessor(org.thoughtcrime.securesms.storage.ContactRecordProcessor) RetryLaterException(org.thoughtcrime.securesms.transport.RetryLaterException)

Example 10 with Stopwatch

use of org.thoughtcrime.securesms.util.Stopwatch in project Signal-Android by signalapp.

the class RegistrationLockFragment method handleSuccessfulPinEntry.

@Override
protected void handleSuccessfulPinEntry(@NonNull String pin) {
    SignalStore.pinValues().setKeyboardType(getPinEntryKeyboardType());
    SimpleTask.run(() -> {
        SignalStore.onboarding().clearAll();
        Stopwatch stopwatch = new Stopwatch("RegistrationLockRestore");
        ApplicationDependencies.getJobManager().runSynchronously(new StorageAccountRestoreJob(), StorageAccountRestoreJob.LIFESPAN);
        stopwatch.split("AccountRestore");
        ApplicationDependencies.getJobManager().runSynchronously(new StorageSyncJob(), TimeUnit.SECONDS.toMillis(10));
        stopwatch.split("ContactRestore");
        try {
            FeatureFlags.refreshSync();
        } catch (IOException e) {
            Log.w(TAG, "Failed to refresh flags.", e);
        }
        stopwatch.split("FeatureFlags");
        stopwatch.stop(TAG);
        return null;
    }, none -> {
        cancelSpinning(pinButton);
        SafeNavigation.safeNavigate(Navigation.findNavController(requireView()), RegistrationLockFragmentDirections.actionSuccessfulRegistration());
    });
}
Also used : StorageSyncJob(org.thoughtcrime.securesms.jobs.StorageSyncJob) StorageAccountRestoreJob(org.thoughtcrime.securesms.jobs.StorageAccountRestoreJob) Stopwatch(org.thoughtcrime.securesms.util.Stopwatch) IOException(java.io.IOException)

Aggregations

Stopwatch (org.thoughtcrime.securesms.util.Stopwatch)42 NonNull (androidx.annotation.NonNull)20 IOException (java.io.IOException)16 Nullable (androidx.annotation.Nullable)14 Context (android.content.Context)12 ArrayList (java.util.ArrayList)12 Log (org.signal.core.util.logging.Log)12 WorkerThread (androidx.annotation.WorkerThread)10 List (java.util.List)10 Recipient (org.thoughtcrime.securesms.recipients.Recipient)10 RecipientId (org.thoughtcrime.securesms.recipients.RecipientId)10 Util (org.thoughtcrime.securesms.util.Util)10 Stream (com.annimon.stream.Stream)8 Collections (java.util.Collections)8 LinkedList (java.util.LinkedList)8 Set (java.util.Set)8 ApplicationDependencies (org.thoughtcrime.securesms.dependencies.ApplicationDependencies)8 SignalStore (org.thoughtcrime.securesms.keyvalue.SignalStore)8 Optional (org.whispersystems.libsignal.util.guava.Optional)8 Cursor (android.database.Cursor)6