use of org.thoughtcrime.securesms.database.model.Mention in project Signal-Android by signalapp.
the class MentionUtil method mentionsToBodyRangeList.
@Nullable
public static BodyRangeList mentionsToBodyRangeList(@Nullable List<Mention> mentions) {
if (mentions == null || mentions.isEmpty()) {
return null;
}
BodyRangeList.Builder builder = BodyRangeList.newBuilder();
for (Mention mention : mentions) {
String uuid = Recipient.resolved(mention.getRecipientId()).requireServiceId().toString();
builder.addRanges(BodyRangeList.BodyRange.newBuilder().setMentionUuid(uuid).setStart(mention.getStart()).setLength(mention.getLength()));
}
return builder.build();
}
use of org.thoughtcrime.securesms.database.model.Mention in project Signal-Android by signalapp.
the class MmsDatabase method getOutgoingMessage.
@Override
public OutgoingMediaMessage getOutgoingMessage(long messageId) throws MmsException, NoSuchMessageException {
AttachmentDatabase attachmentDatabase = SignalDatabase.attachments();
MentionDatabase mentionDatabase = SignalDatabase.mentions();
Cursor cursor = null;
try {
cursor = rawQuery(RAW_ID_WHERE, new String[] { String.valueOf(messageId) });
if (cursor != null && cursor.moveToNext()) {
List<DatabaseAttachment> associatedAttachments = attachmentDatabase.getAttachmentsForMessage(messageId);
List<Mention> mentions = mentionDatabase.getMentionsForMessage(messageId);
long outboxType = cursor.getLong(cursor.getColumnIndexOrThrow(MESSAGE_BOX));
String body = cursor.getString(cursor.getColumnIndexOrThrow(BODY));
long timestamp = cursor.getLong(cursor.getColumnIndexOrThrow(NORMALIZED_DATE_SENT));
int subscriptionId = cursor.getInt(cursor.getColumnIndexOrThrow(SUBSCRIPTION_ID));
long expiresIn = cursor.getLong(cursor.getColumnIndexOrThrow(EXPIRES_IN));
boolean viewOnce = cursor.getLong(cursor.getColumnIndexOrThrow(VIEW_ONCE)) == 1;
long recipientId = cursor.getLong(cursor.getColumnIndexOrThrow(RECIPIENT_ID));
long threadId = cursor.getLong(cursor.getColumnIndexOrThrow(THREAD_ID));
int distributionType = SignalDatabase.threads().getDistributionType(threadId);
String mismatchDocument = cursor.getString(cursor.getColumnIndexOrThrow(MmsDatabase.MISMATCHED_IDENTITIES));
String networkDocument = cursor.getString(cursor.getColumnIndexOrThrow(MmsDatabase.NETWORK_FAILURE));
long quoteId = cursor.getLong(cursor.getColumnIndexOrThrow(QUOTE_ID));
long quoteAuthor = cursor.getLong(cursor.getColumnIndexOrThrow(QUOTE_AUTHOR));
String quoteText = cursor.getString(cursor.getColumnIndexOrThrow(QUOTE_BODY));
boolean quoteMissing = cursor.getInt(cursor.getColumnIndexOrThrow(QUOTE_MISSING)) == 1;
List<Attachment> quoteAttachments = Stream.of(associatedAttachments).filter(Attachment::isQuote).map(a -> (Attachment) a).toList();
List<Mention> quoteMentions = parseQuoteMentions(context, cursor);
List<Contact> contacts = getSharedContacts(cursor, associatedAttachments);
Set<Attachment> contactAttachments = new HashSet<>(Stream.of(contacts).map(Contact::getAvatarAttachment).filter(a -> a != null).toList());
List<LinkPreview> previews = getLinkPreviews(cursor, associatedAttachments);
Set<Attachment> previewAttachments = Stream.of(previews).filter(lp -> lp.getThumbnail().isPresent()).map(lp -> lp.getThumbnail().get()).collect(Collectors.toSet());
List<Attachment> attachments = Stream.of(associatedAttachments).filterNot(Attachment::isQuote).filterNot(contactAttachments::contains).filterNot(previewAttachments::contains).sorted(new DatabaseAttachment.DisplayOrderComparator()).map(a -> (Attachment) a).toList();
Recipient recipient = Recipient.resolved(RecipientId.from(recipientId));
Set<NetworkFailure> networkFailures = new HashSet<>();
Set<IdentityKeyMismatch> mismatches = new HashSet<>();
QuoteModel quote = null;
if (quoteId > 0 && quoteAuthor > 0 && (!TextUtils.isEmpty(quoteText) || !quoteAttachments.isEmpty())) {
quote = new QuoteModel(quoteId, RecipientId.from(quoteAuthor), quoteText, quoteMissing, quoteAttachments, quoteMentions);
}
if (!TextUtils.isEmpty(mismatchDocument)) {
try {
mismatches = JsonUtils.fromJson(mismatchDocument, IdentityKeyMismatchSet.class).getItems();
} catch (IOException e) {
Log.w(TAG, e);
}
}
if (!TextUtils.isEmpty(networkDocument)) {
try {
networkFailures = JsonUtils.fromJson(networkDocument, NetworkFailureSet.class).getItems();
} catch (IOException e) {
Log.w(TAG, e);
}
}
if (body != null && (Types.isGroupQuit(outboxType) || Types.isGroupUpdate(outboxType))) {
return new OutgoingGroupUpdateMessage(recipient, new MessageGroupContext(body, Types.isGroupV2(outboxType)), attachments, timestamp, 0, false, quote, contacts, previews, mentions);
} else if (Types.isExpirationTimerUpdate(outboxType)) {
return new OutgoingExpirationUpdateMessage(recipient, timestamp, expiresIn);
}
OutgoingMediaMessage message = new OutgoingMediaMessage(recipient, body, attachments, timestamp, subscriptionId, expiresIn, viewOnce, distributionType, quote, contacts, previews, mentions, networkFailures, mismatches);
if (Types.isSecureType(outboxType)) {
return new OutgoingSecureMediaMessage(message);
}
return message;
}
throw new NoSuchMessageException("No record found for id: " + messageId);
} catch (IOException e) {
throw new MmsException(e);
} finally {
if (cursor != null)
cursor.close();
}
}
use of org.thoughtcrime.securesms.database.model.Mention in project Signal-Android by signalapp.
the class MultiShareSender method sendSync.
@WorkerThread
public static MultiShareSendResultCollection sendSync(@NonNull MultiShareArgs multiShareArgs) {
List<MultiShareSendResult> results = new ArrayList<>(multiShareArgs.getShareContactAndThreads().size());
Context context = ApplicationDependencies.getApplication();
boolean isMmsEnabled = Util.isMmsCapable(context);
String message = multiShareArgs.getDraftText();
SlideDeck slideDeck;
try {
slideDeck = buildSlideDeck(context, multiShareArgs);
} catch (SlideNotFoundException e) {
Log.w(TAG, "Could not create slide for media message");
for (ShareContactAndThread shareContactAndThread : multiShareArgs.getShareContactAndThreads()) {
results.add(new MultiShareSendResult(shareContactAndThread, MultiShareSendResult.Type.GENERIC_ERROR));
}
return new MultiShareSendResultCollection(results);
}
for (ShareContactAndThread shareContactAndThread : multiShareArgs.getShareContactAndThreads()) {
Recipient recipient = Recipient.resolved(shareContactAndThread.getRecipientId());
List<Mention> mentions = getValidMentionsForRecipient(recipient, multiShareArgs.getMentions());
TransportOption transport = resolveTransportOption(context, recipient);
boolean forceSms = recipient.isForceSmsSelection() && transport.isSms();
int subscriptionId = transport.getSimSubscriptionId().or(-1);
long expiresIn = TimeUnit.SECONDS.toMillis(recipient.getExpiresInSeconds());
boolean needsSplit = !transport.isSms() && message != null && message.length() > transport.calculateCharacters(message).maxPrimaryMessageSize;
boolean isMediaMessage = !multiShareArgs.getMedia().isEmpty() || (multiShareArgs.getDataUri() != null && multiShareArgs.getDataUri() != Uri.EMPTY) || multiShareArgs.getStickerLocator() != null || multiShareArgs.getLinkPreview() != null || recipient.isGroup() || recipient.getEmail().isPresent() || !mentions.isEmpty() || needsSplit;
if ((recipient.isMmsGroup() || recipient.getEmail().isPresent()) && !isMmsEnabled) {
results.add(new MultiShareSendResult(shareContactAndThread, MultiShareSendResult.Type.MMS_NOT_ENABLED));
} else if (isMediaMessage) {
sendMediaMessage(context, multiShareArgs, recipient, slideDeck, transport, shareContactAndThread.getThreadId(), forceSms, expiresIn, multiShareArgs.isViewOnce(), subscriptionId, mentions);
results.add(new MultiShareSendResult(shareContactAndThread, MultiShareSendResult.Type.SUCCESS));
} else {
sendTextMessage(context, multiShareArgs, recipient, shareContactAndThread.getThreadId(), forceSms, expiresIn, subscriptionId);
results.add(new MultiShareSendResult(shareContactAndThread, MultiShareSendResult.Type.SUCCESS));
}
// XXX We must do this to avoid sending out messages to the same recipient with the same
// sentTimestamp. If we do this, they'll be considered dupes by the receiver.
ThreadUtil.sleep(5);
}
return new MultiShareSendResultCollection(results);
}
use of org.thoughtcrime.securesms.database.model.Mention in project Signal-Android by signalapp.
the class ConversationParentFragment method onActivityResult.
@Override
public void onActivityResult(final int reqCode, int resultCode, Intent data) {
Log.i(TAG, "onActivityResult called: " + reqCode + ", " + resultCode + " , " + data);
super.onActivityResult(reqCode, resultCode, data);
if ((data == null && reqCode != TAKE_PHOTO && reqCode != SMS_DEFAULT) || (resultCode != Activity.RESULT_OK && reqCode != SMS_DEFAULT)) {
updateLinkPreviewState();
SignalStore.settings().setDefaultSms(Util.isDefaultSmsProvider(requireContext()));
return;
}
switch(reqCode) {
case PICK_DOCUMENT:
setMedia(data.getData(), MediaType.DOCUMENT);
break;
case PICK_AUDIO:
setMedia(data.getData(), MediaType.AUDIO);
break;
case PICK_CONTACT:
if (isSecureText && !isSmsForced()) {
openContactShareEditor(data.getData());
} else {
addAttachmentContactInfo(data.getData());
}
break;
case GET_CONTACT_DETAILS:
sendSharedContact(data.getParcelableArrayListExtra(ContactShareEditActivity.KEY_CONTACTS));
break;
case GROUP_EDIT:
Recipient recipientSnapshot = recipient.get();
onRecipientChanged(recipientSnapshot);
titleView.setTitle(glideRequests, recipientSnapshot);
NotificationChannels.updateContactChannelName(requireContext(), recipientSnapshot);
setBlockedUserState(recipientSnapshot, isSecureText, isDefaultSms);
invalidateOptionsMenu();
break;
case TAKE_PHOTO:
handleImageFromDeviceCameraApp();
break;
case ADD_CONTACT:
SimpleTask.run(() -> {
try {
DirectoryHelper.refreshDirectoryFor(requireContext(), recipient.get(), false);
} catch (IOException e) {
Log.w(TAG, "Failed to refresh user after adding to contacts.");
}
return null;
}, nothing -> onRecipientChanged(recipient.get()));
break;
case PICK_LOCATION:
SignalPlace place = new SignalPlace(PlacePickerActivity.addressFromData(data));
attachmentManager.setLocation(place, getCurrentMediaConstraints());
break;
case PICK_GIF:
onGifSelectSuccess(data.getData(), data.getIntExtra(GiphyActivity.EXTRA_WIDTH, 0), data.getIntExtra(GiphyActivity.EXTRA_HEIGHT, 0));
break;
case SMS_DEFAULT:
initializeSecurity(isSecureText, isDefaultSms);
break;
case MEDIA_SENDER:
MediaSendActivityResult result = MediaSendActivityResult.fromData(data);
if (!Objects.equals(result.getRecipientId(), recipient.getId())) {
Log.w(TAG, "Result's recipientId did not match ours! Result: " + result.getRecipientId() + ", Activity: " + recipient.getId());
Toast.makeText(requireContext(), R.string.ConversationActivity_error_sending_media, Toast.LENGTH_SHORT).show();
return;
}
sendButton.setTransport(result.getTransport());
if (result.isPushPreUpload()) {
sendMediaMessage(result);
return;
}
long expiresIn = TimeUnit.SECONDS.toMillis(recipient.get().getExpiresInSeconds());
int subscriptionId = sendButton.getSelectedTransport().getSimSubscriptionId().or(-1);
boolean initiating = threadId == -1;
QuoteModel quote = result.isViewOnce() ? null : inputPanel.getQuote().orNull();
SlideDeck slideDeck = new SlideDeck();
List<Mention> mentions = new ArrayList<>(result.getMentions());
for (Media mediaItem : result.getNonUploadedMedia()) {
if (MediaUtil.isVideoType(mediaItem.getMimeType())) {
slideDeck.addSlide(new VideoSlide(requireContext(), mediaItem.getUri(), mediaItem.getSize(), mediaItem.isVideoGif(), mediaItem.getWidth(), mediaItem.getHeight(), mediaItem.getCaption().orNull(), mediaItem.getTransformProperties().orNull()));
} else if (MediaUtil.isGif(mediaItem.getMimeType())) {
slideDeck.addSlide(new GifSlide(requireContext(), mediaItem.getUri(), mediaItem.getSize(), mediaItem.getWidth(), mediaItem.getHeight(), mediaItem.isBorderless(), mediaItem.getCaption().orNull()));
} else if (MediaUtil.isImageType(mediaItem.getMimeType())) {
slideDeck.addSlide(new ImageSlide(requireContext(), mediaItem.getUri(), mediaItem.getMimeType(), mediaItem.getSize(), mediaItem.getWidth(), mediaItem.getHeight(), mediaItem.isBorderless(), mediaItem.getCaption().orNull(), null, mediaItem.getTransformProperties().orNull()));
} else {
Log.w(TAG, "Asked to send an unexpected mimeType: '" + mediaItem.getMimeType() + "'. Skipping.");
}
}
final Context context = requireContext().getApplicationContext();
sendMediaMessage(result.getRecipientId(), result.getTransport().isSms(), result.getBody(), slideDeck, quote, Collections.emptyList(), Collections.emptyList(), mentions, expiresIn, result.isViewOnce(), subscriptionId, initiating, true, null).addListener(new AssertedSuccessListener<Void>() {
@Override
public void onSuccess(Void result) {
AsyncTask.THREAD_POOL_EXECUTOR.execute(() -> {
Stream.of(slideDeck.getSlides()).map(Slide::getUri).withoutNulls().filter(BlobProvider::isAuthority).forEach(uri -> BlobProvider.getInstance().delete(context, uri));
});
}
});
break;
}
}
use of org.thoughtcrime.securesms.database.model.Mention in project Signal-Android by signalapp.
the class ConversationParentFragment method getDraftsForCurrentState.
private Drafts getDraftsForCurrentState() {
Drafts drafts = new Drafts();
if (recipient.get().isGroup() && !recipient.get().isActiveGroup()) {
return drafts;
}
if (!Util.isEmpty(composeText)) {
drafts.add(new Draft(Draft.TEXT, composeText.getTextTrimmed().toString()));
List<Mention> draftMentions = composeText.getMentions();
if (!draftMentions.isEmpty()) {
drafts.add(new Draft(Draft.MENTION, Base64.encodeBytes(MentionUtil.mentionsToBodyRangeList(draftMentions).toByteArray())));
}
}
for (Slide slide : attachmentManager.buildSlideDeck().getSlides()) {
if (slide.hasAudio() && slide.getUri() != null)
drafts.add(new Draft(Draft.AUDIO, slide.getUri().toString()));
else if (slide.hasVideo() && slide.getUri() != null)
drafts.add(new Draft(Draft.VIDEO, slide.getUri().toString()));
else if (slide.hasLocation())
drafts.add(new Draft(Draft.LOCATION, ((LocationSlide) slide).getPlace().serialize()));
else if (slide.hasImage() && slide.getUri() != null)
drafts.add(new Draft(Draft.IMAGE, slide.getUri().toString()));
}
Optional<QuoteModel> quote = inputPanel.getQuote();
if (quote.isPresent()) {
drafts.add(new Draft(Draft.QUOTE, new QuoteId(quote.get().getId(), quote.get().getAuthor()).serialize()));
}
Draft voiceNoteDraft = draftViewModel.getVoiceNoteDraft();
if (voiceNoteDraft != null) {
drafts.add(voiceNoteDraft);
}
return drafts;
}
Aggregations