Search in sources :

Example 6 with NetworkFailure

use of org.thoughtcrime.securesms.database.documents.NetworkFailure in project Signal-Android by WhisperSystems.

the class PushGroupSendJob method onPushSend.

@Override
public void onPushSend() throws IOException, MmsException, NoSuchMessageException, RetryLaterException {
    SignalLocalMetrics.GroupMessageSend.onJobStarted(messageId);
    MessageDatabase database = SignalDatabase.mms();
    OutgoingMediaMessage message = database.getOutgoingMessage(messageId);
    long threadId = database.getMessageRecord(messageId).getThreadId();
    Set<NetworkFailure> existingNetworkFailures = message.getNetworkFailures();
    Set<IdentityKeyMismatch> existingIdentityMismatches = message.getIdentityKeyMismatches();
    ApplicationDependencies.getJobManager().cancelAllInQueue(TypingSendJob.getQueue(threadId));
    if (database.isSent(messageId)) {
        log(TAG, String.valueOf(message.getSentTimeMillis()), "Message " + messageId + " was already sent. Ignoring.");
        return;
    }
    Recipient groupRecipient = message.getRecipient().resolve();
    if (!groupRecipient.isPushGroup()) {
        throw new MmsException("Message recipient isn't a group!");
    }
    if (groupRecipient.isPushV1Group()) {
        throw new MmsException("No GV1 messages can be sent anymore!");
    }
    try {
        log(TAG, String.valueOf(message.getSentTimeMillis()), "Sending message: " + messageId + ", Recipient: " + message.getRecipient().getId() + ", Thread: " + threadId + ", Attachments: " + buildAttachmentString(message.getAttachments()));
        if (!groupRecipient.resolve().isProfileSharing() && !database.isGroupQuitMessage(messageId)) {
            RecipientUtil.shareProfileIfFirstSecureMessage(context, groupRecipient);
        }
        List<Recipient> target;
        if (filterRecipient != null)
            target = Collections.singletonList(Recipient.resolved(filterRecipient));
        else if (!existingNetworkFailures.isEmpty())
            target = Stream.of(existingNetworkFailures).map(nf -> nf.getRecipientId(context)).distinct().map(Recipient::resolved).toList();
        else
            target = Stream.of(getGroupMessageRecipients(groupRecipient.requireGroupId(), messageId)).distinctBy(Recipient::getId).toList();
        RecipientAccessList accessList = new RecipientAccessList(target);
        List<SendMessageResult> results = deliver(message, groupRecipient, target);
        Log.i(TAG, JobLogger.format(this, "Finished send."));
        List<NetworkFailure> networkFailures = Stream.of(results).filter(SendMessageResult::isNetworkFailure).map(result -> new NetworkFailure(accessList.requireIdByAddress(result.getAddress()))).toList();
        List<IdentityKeyMismatch> identityMismatches = Stream.of(results).filter(result -> result.getIdentityFailure() != null).map(result -> new IdentityKeyMismatch(accessList.requireIdByAddress(result.getAddress()), result.getIdentityFailure().getIdentityKey())).toList();
        ProofRequiredException proofRequired = Stream.of(results).filter(r -> r.getProofRequiredFailure() != null).findLast().map(SendMessageResult::getProofRequiredFailure).orElse(null);
        List<SendMessageResult> successes = Stream.of(results).filter(result -> result.getSuccess() != null).toList();
        List<Pair<RecipientId, Boolean>> successUnidentifiedStatus = Stream.of(successes).map(result -> new Pair<>(accessList.requireIdByAddress(result.getAddress()), result.getSuccess().isUnidentified())).toList();
        Set<RecipientId> successIds = Stream.of(successUnidentifiedStatus).map(Pair::first).collect(Collectors.toSet());
        List<NetworkFailure> resolvedNetworkFailures = Stream.of(existingNetworkFailures).filter(failure -> successIds.contains(failure.getRecipientId(context))).toList();
        List<IdentityKeyMismatch> resolvedIdentityFailures = Stream.of(existingIdentityMismatches).filter(failure -> successIds.contains(failure.getRecipientId(context))).toList();
        List<RecipientId> unregisteredRecipients = Stream.of(results).filter(SendMessageResult::isUnregisteredFailure).map(result -> RecipientId.from(result.getAddress())).toList();
        if (networkFailures.size() > 0 || identityMismatches.size() > 0 || proofRequired != null || unregisteredRecipients.size() > 0) {
            Log.w(TAG, String.format(Locale.US, "Failed to send to some recipients. Network: %d, Identity: %d, ProofRequired: %s, Unregistered: %d", networkFailures.size(), identityMismatches.size(), proofRequired != null, unregisteredRecipients.size()));
        }
        RecipientDatabase recipientDatabase = SignalDatabase.recipients();
        for (RecipientId unregistered : unregisteredRecipients) {
            recipientDatabase.markUnregistered(unregistered);
        }
        existingNetworkFailures.removeAll(resolvedNetworkFailures);
        existingNetworkFailures.addAll(networkFailures);
        database.setNetworkFailures(messageId, existingNetworkFailures);
        existingIdentityMismatches.removeAll(resolvedIdentityFailures);
        existingIdentityMismatches.addAll(identityMismatches);
        database.setMismatchedIdentities(messageId, existingIdentityMismatches);
        SignalDatabase.groupReceipts().setUnidentified(successUnidentifiedStatus, messageId);
        if (proofRequired != null) {
            handleProofRequiredException(proofRequired, groupRecipient, threadId, messageId, true);
        }
        if (existingNetworkFailures.isEmpty() && networkFailures.isEmpty() && identityMismatches.isEmpty() && existingIdentityMismatches.isEmpty()) {
            database.markAsSent(messageId, true);
            markAttachmentsUploaded(messageId, message);
            if (message.getExpiresIn() > 0 && !message.isExpirationUpdate()) {
                database.markExpireStarted(messageId);
                ApplicationDependencies.getExpiringMessageManager().scheduleDeletion(messageId, true, message.getExpiresIn());
            }
            if (message.isViewOnce()) {
                SignalDatabase.attachments().deleteAttachmentFilesForViewOnceMessage(messageId);
            }
        } else if (!identityMismatches.isEmpty()) {
            Log.w(TAG, "Failing because there were " + identityMismatches.size() + " identity mismatches.");
            database.markAsSentFailed(messageId);
            notifyMediaMessageDeliveryFailed(context, messageId);
            Set<RecipientId> mismatchRecipientIds = Stream.of(identityMismatches).map(mismatch -> mismatch.getRecipientId(context)).collect(Collectors.toSet());
            RetrieveProfileJob.enqueue(mismatchRecipientIds);
        } else if (!networkFailures.isEmpty()) {
            Log.w(TAG, "Retrying because there were " + networkFailures.size() + " network failures.");
            throw new RetryLaterException();
        }
    } catch (UntrustedIdentityException | UndeliverableMessageException e) {
        warn(TAG, String.valueOf(message.getSentTimeMillis()), e);
        database.markAsSentFailed(messageId);
        notifyMediaMessageDeliveryFailed(context, messageId);
    }
    SignalLocalMetrics.GroupMessageSend.onJobFinished(messageId);
}
Also used : ServerRejectedException(org.whispersystems.signalservice.api.push.exceptions.ServerRejectedException) SignalServiceDataMessage(org.whispersystems.signalservice.api.messages.SignalServiceDataMessage) SendMessageResult(org.whispersystems.signalservice.api.messages.SendMessageResult) NonNull(androidx.annotation.NonNull) Data(org.thoughtcrime.securesms.jobmanager.Data) JobManager(org.thoughtcrime.securesms.jobmanager.JobManager) RecipientUtil(org.thoughtcrime.securesms.recipients.RecipientUtil) Quote(org.whispersystems.signalservice.api.messages.SignalServiceDataMessage.Quote) MessageGroupContext(org.thoughtcrime.securesms.mms.MessageGroupContext) RecipientId(org.thoughtcrime.securesms.recipients.RecipientId) Locale(java.util.Locale) Recipient(org.thoughtcrime.securesms.recipients.Recipient) OutgoingGroupUpdateMessage(org.thoughtcrime.securesms.mms.OutgoingGroupUpdateMessage) ApplicationDependencies(org.thoughtcrime.securesms.dependencies.ApplicationDependencies) SignalServiceAttachment(org.whispersystems.signalservice.api.messages.SignalServiceAttachment) Set(java.util.Set) GroupDatabase(org.thoughtcrime.securesms.database.GroupDatabase) UndeliverableMessageException(org.thoughtcrime.securesms.transport.UndeliverableMessageException) ByteString(com.google.protobuf.ByteString) Log(org.signal.core.util.logging.Log) GroupContextV2(org.whispersystems.signalservice.internal.push.SignalServiceProtos.GroupContextV2) List(java.util.List) Nullable(androidx.annotation.Nullable) SignalServiceGroupV2(org.whispersystems.signalservice.api.messages.SignalServiceGroupV2) GroupId(org.thoughtcrime.securesms.groups.GroupId) Job(org.thoughtcrime.securesms.jobmanager.Job) SharedContact(org.whispersystems.signalservice.api.messages.shared.SharedContact) MessageDatabase(org.thoughtcrime.securesms.database.MessageDatabase) GroupUtil(org.thoughtcrime.securesms.util.GroupUtil) NoSuchMessageException(org.thoughtcrime.securesms.database.NoSuchMessageException) Attachment(org.thoughtcrime.securesms.attachments.Attachment) OutgoingMediaMessage(org.thoughtcrime.securesms.mms.OutgoingMediaMessage) Preview(org.whispersystems.signalservice.api.messages.SignalServiceDataMessage.Preview) Context(android.content.Context) RecipientAccessList(org.thoughtcrime.securesms.util.RecipientAccessList) SignalDatabase(org.thoughtcrime.securesms.database.SignalDatabase) RetryLaterException(org.thoughtcrime.securesms.transport.RetryLaterException) ContentHint(org.whispersystems.signalservice.api.crypto.ContentHint) Stream(com.annimon.stream.Stream) JobLogger(org.thoughtcrime.securesms.jobmanager.JobLogger) SignalLocalMetrics(org.thoughtcrime.securesms.util.SignalLocalMetrics) WorkerThread(androidx.annotation.WorkerThread) RecipientDatabase(org.thoughtcrime.securesms.database.RecipientDatabase) Pair(org.whispersystems.libsignal.util.Pair) GroupSendUtil(org.thoughtcrime.securesms.messages.GroupSendUtil) GroupReceiptInfo(org.thoughtcrime.securesms.database.GroupReceiptDatabase.GroupReceiptInfo) MessageId(org.thoughtcrime.securesms.database.model.MessageId) Collectors(com.annimon.stream.Collectors) GroupReceiptDatabase(org.thoughtcrime.securesms.database.GroupReceiptDatabase) IdentityKeyMismatch(org.thoughtcrime.securesms.database.documents.IdentityKeyMismatch) MmsException(org.thoughtcrime.securesms.mms.MmsException) NetworkConstraint(org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint) IOException(java.io.IOException) Optional(org.whispersystems.libsignal.util.guava.Optional) TimeUnit(java.util.concurrent.TimeUnit) ProofRequiredException(org.whispersystems.signalservice.api.push.exceptions.ProofRequiredException) UntrustedIdentityException(org.whispersystems.signalservice.api.crypto.UntrustedIdentityException) NetworkFailure(org.thoughtcrime.securesms.database.documents.NetworkFailure) Collections(java.util.Collections) RecipientId(org.thoughtcrime.securesms.recipients.RecipientId) Set(java.util.Set) UntrustedIdentityException(org.whispersystems.signalservice.api.crypto.UntrustedIdentityException) OutgoingMediaMessage(org.thoughtcrime.securesms.mms.OutgoingMediaMessage) RecipientDatabase(org.thoughtcrime.securesms.database.RecipientDatabase) MmsException(org.thoughtcrime.securesms.mms.MmsException) UndeliverableMessageException(org.thoughtcrime.securesms.transport.UndeliverableMessageException) Pair(org.whispersystems.libsignal.util.Pair) MessageDatabase(org.thoughtcrime.securesms.database.MessageDatabase) Recipient(org.thoughtcrime.securesms.recipients.Recipient) ProofRequiredException(org.whispersystems.signalservice.api.push.exceptions.ProofRequiredException) NetworkFailure(org.thoughtcrime.securesms.database.documents.NetworkFailure) IdentityKeyMismatch(org.thoughtcrime.securesms.database.documents.IdentityKeyMismatch) SendMessageResult(org.whispersystems.signalservice.api.messages.SendMessageResult) RetryLaterException(org.thoughtcrime.securesms.transport.RetryLaterException) RecipientAccessList(org.thoughtcrime.securesms.util.RecipientAccessList)

Example 7 with NetworkFailure

use of org.thoughtcrime.securesms.database.documents.NetworkFailure in project Signal-Android by WhisperSystems.

the class MessageDetailsRepository method getRecipientDeliveryStatusesInternal.

@WorkerThread
@NonNull
private MessageDetails getRecipientDeliveryStatusesInternal(@NonNull MessageRecord messageRecord) {
    List<RecipientDeliveryStatus> recipients = new LinkedList<>();
    if (!messageRecord.getRecipient().isGroup()) {
        recipients.add(new RecipientDeliveryStatus(messageRecord, messageRecord.getRecipient(), getStatusFor(messageRecord), messageRecord.isUnidentified(), messageRecord.getReceiptTimestamp(), getNetworkFailure(messageRecord, messageRecord.getRecipient()), getKeyMismatchFailure(messageRecord, messageRecord.getRecipient())));
    } else {
        List<GroupReceiptDatabase.GroupReceiptInfo> receiptInfoList = SignalDatabase.groupReceipts().getGroupReceiptInfo(messageRecord.getId());
        if (receiptInfoList.isEmpty()) {
            List<Recipient> group = SignalDatabase.groups().getGroupMembers(messageRecord.getRecipient().requireGroupId(), GroupDatabase.MemberSet.FULL_MEMBERS_EXCLUDING_SELF);
            for (Recipient recipient : group) {
                recipients.add(new RecipientDeliveryStatus(messageRecord, recipient, RecipientDeliveryStatus.Status.UNKNOWN, false, messageRecord.getReceiptTimestamp(), getNetworkFailure(messageRecord, recipient), getKeyMismatchFailure(messageRecord, recipient)));
            }
        } else {
            for (GroupReceiptDatabase.GroupReceiptInfo info : receiptInfoList) {
                Recipient recipient = Recipient.resolved(info.getRecipientId());
                NetworkFailure failure = getNetworkFailure(messageRecord, recipient);
                IdentityKeyMismatch mismatch = getKeyMismatchFailure(messageRecord, recipient);
                boolean recipientFailure = failure != null || mismatch != null;
                recipients.add(new RecipientDeliveryStatus(messageRecord, recipient, getStatusFor(info.getStatus(), messageRecord.isPending(), recipientFailure), info.isUnidentified(), info.getTimestamp(), failure, mismatch));
            }
        }
    }
    return new MessageDetails(ConversationMessageFactory.createWithUnresolvedData(context, messageRecord), recipients);
}
Also used : GroupReceiptDatabase(org.thoughtcrime.securesms.database.GroupReceiptDatabase) Recipient(org.thoughtcrime.securesms.recipients.Recipient) NetworkFailure(org.thoughtcrime.securesms.database.documents.NetworkFailure) IdentityKeyMismatch(org.thoughtcrime.securesms.database.documents.IdentityKeyMismatch) LinkedList(java.util.LinkedList) WorkerThread(androidx.annotation.WorkerThread) NonNull(androidx.annotation.NonNull)

Example 8 with NetworkFailure

use of org.thoughtcrime.securesms.database.documents.NetworkFailure in project Signal-Android by WhisperSystems.

the class MessageRecipientListItem method setIssueIndicators.

private void setIssueIndicators(final MasterSecret masterSecret, final MessageRecord record, final boolean isPushGroup) {
    final NetworkFailure networkFailure = getNetworkFailure(record);
    final IdentityKeyMismatch keyMismatch = networkFailure == null ? getKeyMismatch(record) : null;
    String errorText = "";
    if (keyMismatch != null) {
        resendButton.setVisibility(View.GONE);
        conflictButton.setVisibility(View.VISIBLE);
        errorText = getContext().getString(R.string.MessageDetailsRecipient_new_safety_number);
        conflictButton.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                new ConfirmIdentityDialog(getContext(), masterSecret, record, keyMismatch).show();
            }
        });
    } else if (networkFailure != null || (!isPushGroup && record.isFailed())) {
        resendButton.setVisibility(View.VISIBLE);
        resendButton.setEnabled(true);
        resendButton.requestFocus();
        conflictButton.setVisibility(View.GONE);
        errorText = getContext().getString(R.string.MessageDetailsRecipient_failed_to_send);
        resendButton.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                resendButton.setVisibility(View.GONE);
                errorDescription.setVisibility(View.GONE);
                actionDescription.setVisibility(View.VISIBLE);
                actionDescription.setText(R.string.message_recipients_list_item__resending);
                new ResendAsyncTask(masterSecret, record, networkFailure).execute();
            }
        });
    } else {
        resendButton.setVisibility(View.GONE);
        conflictButton.setVisibility(View.GONE);
    }
    errorDescription.setText(errorText);
    errorDescription.setVisibility(TextUtils.isEmpty(errorText) ? View.GONE : View.VISIBLE);
}
Also used : NetworkFailure(org.thoughtcrime.securesms.database.documents.NetworkFailure) IdentityKeyMismatch(org.thoughtcrime.securesms.database.documents.IdentityKeyMismatch) FromTextView(org.thoughtcrime.securesms.components.FromTextView) TextView(android.widget.TextView) View(android.view.View) AvatarImageView(org.thoughtcrime.securesms.components.AvatarImageView)

Example 9 with NetworkFailure

use of org.thoughtcrime.securesms.database.documents.NetworkFailure in project Signal-Android by WhisperSystems.

the class PushGroupSendJob method onPushSend.

@Override
public void onPushSend(MasterSecret masterSecret) throws MmsException, IOException, NoSuchMessageException {
    MmsDatabase database = DatabaseFactory.getMmsDatabase(context);
    OutgoingMediaMessage message = database.getOutgoingMessage(masterSecret, messageId);
    try {
        deliver(masterSecret, message, filterRecipientId);
        database.markAsSent(messageId, true);
        markAttachmentsUploaded(messageId, message.getAttachments());
        if (message.getExpiresIn() > 0 && !message.isExpirationUpdate()) {
            database.markExpireStarted(messageId);
            ApplicationContext.getInstance(context).getExpiringMessageManager().scheduleDeletion(messageId, true, message.getExpiresIn());
        }
    } catch (InvalidNumberException | RecipientFormattingException | UndeliverableMessageException e) {
        Log.w(TAG, e);
        database.markAsSentFailed(messageId);
        notifyMediaMessageDeliveryFailed(context, messageId);
    } catch (EncapsulatedExceptions e) {
        Log.w(TAG, e);
        List<NetworkFailure> failures = new LinkedList<>();
        for (NetworkFailureException nfe : e.getNetworkExceptions()) {
            Recipient recipient = RecipientFactory.getRecipientsFromString(context, nfe.getE164number(), false).getPrimaryRecipient();
            failures.add(new NetworkFailure(recipient.getRecipientId()));
        }
        for (UntrustedIdentityException uie : e.getUntrustedIdentityExceptions()) {
            Recipient recipient = RecipientFactory.getRecipientsFromString(context, uie.getE164Number(), false).getPrimaryRecipient();
            database.addMismatchedIdentity(messageId, recipient.getRecipientId(), uie.getIdentityKey());
        }
        database.addFailures(messageId, failures);
        if (e.getNetworkExceptions().isEmpty() && e.getUntrustedIdentityExceptions().isEmpty()) {
            database.markAsSent(messageId, true);
            markAttachmentsUploaded(messageId, message.getAttachments());
        } else {
            database.markAsSentFailed(messageId);
            notifyMediaMessageDeliveryFailed(context, messageId);
        }
    }
}
Also used : EncapsulatedExceptions(org.whispersystems.signalservice.api.push.exceptions.EncapsulatedExceptions) UntrustedIdentityException(org.whispersystems.signalservice.api.crypto.UntrustedIdentityException) InvalidNumberException(org.whispersystems.signalservice.api.util.InvalidNumberException) OutgoingMediaMessage(org.thoughtcrime.securesms.mms.OutgoingMediaMessage) Recipient(org.thoughtcrime.securesms.recipients.Recipient) NetworkFailure(org.thoughtcrime.securesms.database.documents.NetworkFailure) UndeliverableMessageException(org.thoughtcrime.securesms.transport.UndeliverableMessageException) LinkedList(java.util.LinkedList) List(java.util.List) NetworkFailureException(org.whispersystems.signalservice.api.push.exceptions.NetworkFailureException) RecipientFormattingException(org.thoughtcrime.securesms.recipients.RecipientFormattingException) MmsDatabase(org.thoughtcrime.securesms.database.MmsDatabase)

Example 10 with NetworkFailure

use of org.thoughtcrime.securesms.database.documents.NetworkFailure in project Signal-Android by signalapp.

the class MessageRecipientListItem method setIssueIndicators.

private void setIssueIndicators(final MessageRecord record, final boolean isPushGroup) {
    final NetworkFailure networkFailure = getNetworkFailure(record);
    final IdentityKeyMismatch keyMismatch = networkFailure == null ? getKeyMismatch(record) : null;
    String errorText = "";
    if (keyMismatch != null) {
        resendButton.setVisibility(View.GONE);
        conflictButton.setVisibility(View.VISIBLE);
        errorText = getContext().getString(R.string.MessageDetailsRecipient_new_safety_number);
        conflictButton.setOnClickListener(v -> new ConfirmIdentityDialog(getContext(), record, keyMismatch).show());
    } else if (networkFailure != null || (!isPushGroup && record.isFailed())) {
        resendButton.setVisibility(View.VISIBLE);
        resendButton.setEnabled(true);
        resendButton.requestFocus();
        conflictButton.setVisibility(View.GONE);
        errorText = getContext().getString(R.string.MessageDetailsRecipient_failed_to_send);
        resendButton.setOnClickListener(v -> {
            resendButton.setVisibility(View.GONE);
            errorDescription.setVisibility(View.GONE);
            actionDescription.setVisibility(View.VISIBLE);
            actionDescription.setText(R.string.message_recipients_list_item__resending);
            new ResendAsyncTask(record, networkFailure).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
        });
    } else {
        if (record.isOutgoing()) {
            if (member.getDeliveryStatus() == RecipientDeliveryStatus.Status.PENDING || member.getDeliveryStatus() == RecipientDeliveryStatus.Status.UNKNOWN) {
                deliveryStatusView.setVisibility(View.GONE);
            } else if (member.getDeliveryStatus() == RecipientDeliveryStatus.Status.READ) {
                deliveryStatusView.setRead();
                deliveryStatusView.setVisibility(View.VISIBLE);
            } else if (member.getDeliveryStatus() == RecipientDeliveryStatus.Status.DELIVERED) {
                deliveryStatusView.setDelivered();
                deliveryStatusView.setVisibility(View.VISIBLE);
            } else if (member.getDeliveryStatus() == RecipientDeliveryStatus.Status.SENT) {
                deliveryStatusView.setSent();
                deliveryStatusView.setVisibility(View.VISIBLE);
            }
        } else {
            deliveryStatusView.setVisibility(View.GONE);
        }
        resendButton.setVisibility(View.GONE);
        conflictButton.setVisibility(View.GONE);
    }
    errorDescription.setText(errorText);
    errorDescription.setVisibility(TextUtils.isEmpty(errorText) ? View.GONE : View.VISIBLE);
}
Also used : Context(android.content.Context) MessageSender(org.thoughtcrime.securesms.sms.MessageSender) AsyncTask(android.os.AsyncTask) IdentityKeyMismatch(org.thoughtcrime.securesms.database.documents.IdentityKeyMismatch) Util(org.thoughtcrime.securesms.util.Util) DatabaseFactory(org.thoughtcrime.securesms.database.DatabaseFactory) TextUtils(android.text.TextUtils) MessageRecord(org.thoughtcrime.securesms.database.model.MessageRecord) SuppressLint(android.annotation.SuppressLint) FromTextView(org.thoughtcrime.securesms.components.FromTextView) TextView(android.widget.TextView) RecipientModifiedListener(org.thoughtcrime.securesms.recipients.RecipientModifiedListener) AttributeSet(android.util.AttributeSet) NetworkFailure(org.thoughtcrime.securesms.database.documents.NetworkFailure) RecipientDeliveryStatus(org.thoughtcrime.securesms.MessageDetailsRecipientAdapter.RecipientDeliveryStatus) DeliveryStatusView(org.thoughtcrime.securesms.components.DeliveryStatusView) View(android.view.View) Button(android.widget.Button) RelativeLayout(android.widget.RelativeLayout) AvatarImageView(org.thoughtcrime.securesms.components.AvatarImageView) GlideRequests(org.thoughtcrime.securesms.mms.GlideRequests) Recipient(org.thoughtcrime.securesms.recipients.Recipient) MmsDatabase(org.thoughtcrime.securesms.database.MmsDatabase) NetworkFailure(org.thoughtcrime.securesms.database.documents.NetworkFailure) IdentityKeyMismatch(org.thoughtcrime.securesms.database.documents.IdentityKeyMismatch)

Aggregations

NetworkFailure (org.thoughtcrime.securesms.database.documents.NetworkFailure)12 IdentityKeyMismatch (org.thoughtcrime.securesms.database.documents.IdentityKeyMismatch)11 Recipient (org.thoughtcrime.securesms.recipients.Recipient)11 NonNull (androidx.annotation.NonNull)9 Context (android.content.Context)7 LinkedList (java.util.LinkedList)7 List (java.util.List)7 OutgoingMediaMessage (org.thoughtcrime.securesms.mms.OutgoingMediaMessage)7 Nullable (androidx.annotation.Nullable)6 WorkerThread (androidx.annotation.WorkerThread)6 Collectors (com.annimon.stream.Collectors)6 Stream (com.annimon.stream.Stream)6 IOException (java.io.IOException)6 Collections (java.util.Collections)6 Set (java.util.Set)6 Log (org.signal.core.util.logging.Log)6 Attachment (org.thoughtcrime.securesms.attachments.Attachment)6 GroupReceiptDatabase (org.thoughtcrime.securesms.database.GroupReceiptDatabase)6 MessageId (org.thoughtcrime.securesms.database.model.MessageId)6 ApplicationDependencies (org.thoughtcrime.securesms.dependencies.ApplicationDependencies)6