Search in sources :

Example 31 with Pair

use of org.whispersystems.libsignal.util.Pair in project Signal-Android by WhisperSystems.

the class MmsDatabase method setTimestampRead.

@Override
@NonNull
MmsSmsDatabase.TimestampReadResult setTimestampRead(SyncMessageId messageId, long proposedExpireStarted, @NonNull Map<Long, Long> threadToLatestRead) {
    SQLiteDatabase database = databaseHelper.getSignalWritableDatabase();
    List<Pair<Long, Long>> expiring = new LinkedList<>();
    String[] projection = new String[] { ID, THREAD_ID, MESSAGE_BOX, EXPIRES_IN, EXPIRE_STARTED, RECIPIENT_ID };
    String query = DATE_SENT + " = ?";
    String[] args = SqlUtil.buildArgs(messageId.getTimetamp());
    List<Long> threads = new LinkedList<>();
    try (Cursor cursor = database.query(TABLE_NAME, projection, query, args, null, null, null)) {
        while (cursor.moveToNext()) {
            RecipientId theirRecipientId = RecipientId.from(cursor.getLong(cursor.getColumnIndexOrThrow(RECIPIENT_ID)));
            RecipientId ourRecipientId = messageId.getRecipientId();
            if (ourRecipientId.equals(theirRecipientId) || Recipient.resolved(theirRecipientId).isGroup() || ourRecipientId.equals(Recipient.self().getId())) {
                long id = cursor.getLong(cursor.getColumnIndexOrThrow(ID));
                long threadId = cursor.getLong(cursor.getColumnIndexOrThrow(THREAD_ID));
                long expiresIn = cursor.getLong(cursor.getColumnIndexOrThrow(EXPIRES_IN));
                long expireStarted = cursor.getLong(cursor.getColumnIndexOrThrow(EXPIRE_STARTED));
                expireStarted = expireStarted > 0 ? Math.min(proposedExpireStarted, expireStarted) : proposedExpireStarted;
                ContentValues values = new ContentValues();
                values.put(READ, 1);
                values.put(REACTIONS_UNREAD, 0);
                values.put(REACTIONS_LAST_SEEN, System.currentTimeMillis());
                if (expiresIn > 0) {
                    values.put(EXPIRE_STARTED, expireStarted);
                    expiring.add(new Pair<>(id, expiresIn));
                }
                database.update(TABLE_NAME, values, ID_WHERE, SqlUtil.buildArgs(id));
                threads.add(threadId);
                Long latest = threadToLatestRead.get(threadId);
                threadToLatestRead.put(threadId, (latest != null) ? Math.max(latest, messageId.getTimetamp()) : messageId.getTimetamp());
            }
        }
    }
    return new MmsSmsDatabase.TimestampReadResult(expiring, threads);
}
Also used : ContentValues(android.content.ContentValues) RecipientId(org.thoughtcrime.securesms.recipients.RecipientId) Cursor(android.database.Cursor) LinkedList(java.util.LinkedList) Pair(org.whispersystems.libsignal.util.Pair) NonNull(androidx.annotation.NonNull)

Example 32 with Pair

use of org.whispersystems.libsignal.util.Pair in project Signal-Android by WhisperSystems.

the class SmsDatabase method setTimestampRead.

@Override
@NonNull
MmsSmsDatabase.TimestampReadResult setTimestampRead(SyncMessageId messageId, long proposedExpireStarted, @NonNull Map<Long, Long> threadToLatestRead) {
    SQLiteDatabase database = databaseHelper.getSignalWritableDatabase();
    List<Pair<Long, Long>> expiring = new LinkedList<>();
    String[] projection = new String[] { ID, THREAD_ID, RECIPIENT_ID, TYPE, EXPIRES_IN, EXPIRE_STARTED };
    String query = DATE_SENT + " = ?";
    String[] args = SqlUtil.buildArgs(messageId.getTimetamp());
    List<Long> threads = new LinkedList<>();
    try (Cursor cursor = database.query(TABLE_NAME, projection, query, args, null, null, null)) {
        while (cursor.moveToNext()) {
            RecipientId theirRecipientId = messageId.getRecipientId();
            RecipientId outRecipientId = RecipientId.from(cursor.getLong(cursor.getColumnIndexOrThrow(RECIPIENT_ID)));
            if (outRecipientId.equals(theirRecipientId) || theirRecipientId.equals(Recipient.self().getId())) {
                long id = cursor.getLong(cursor.getColumnIndexOrThrow(ID));
                long threadId = cursor.getLong(cursor.getColumnIndexOrThrow(THREAD_ID));
                long expiresIn = cursor.getLong(cursor.getColumnIndexOrThrow(EXPIRES_IN));
                long expireStarted = cursor.getLong(cursor.getColumnIndexOrThrow(EXPIRE_STARTED));
                expireStarted = expireStarted > 0 ? Math.min(proposedExpireStarted, expireStarted) : proposedExpireStarted;
                ContentValues contentValues = new ContentValues();
                contentValues.put(READ, 1);
                contentValues.put(REACTIONS_UNREAD, 0);
                contentValues.put(REACTIONS_LAST_SEEN, System.currentTimeMillis());
                if (expiresIn > 0) {
                    contentValues.put(EXPIRE_STARTED, expireStarted);
                    expiring.add(new Pair<>(id, expiresIn));
                }
                database.update(TABLE_NAME, contentValues, ID_WHERE, SqlUtil.buildArgs(id));
                threads.add(threadId);
                Long latest = threadToLatestRead.get(threadId);
                threadToLatestRead.put(threadId, (latest != null) ? Math.max(latest, messageId.getTimetamp()) : messageId.getTimetamp());
            }
        }
    }
    return new MmsSmsDatabase.TimestampReadResult(expiring, threads);
}
Also used : ContentValues(android.content.ContentValues) RecipientId(org.thoughtcrime.securesms.recipients.RecipientId) Cursor(android.database.Cursor) LinkedList(java.util.LinkedList) Pair(org.whispersystems.libsignal.util.Pair) NonNull(androidx.annotation.NonNull)

Example 33 with Pair

use of org.whispersystems.libsignal.util.Pair in project Signal-Android by WhisperSystems.

the class ConversationParentFragment method initializeIdentityRecords.

private ListenableFuture<Boolean> initializeIdentityRecords() {
    final SettableFuture<Boolean> future = new SettableFuture<>();
    final Context context = requireContext().getApplicationContext();
    if (SignalStore.account().getAci() == null || SignalStore.account().getPni() == null) {
        Log.w(TAG, "Not registered! Skipping initializeIdentityRecords()");
        future.set(false);
        return future;
    }
    new AsyncTask<Recipient, Void, Pair<IdentityRecordList, String>>() {

        @Override
        @NonNull
        protected Pair<IdentityRecordList, String> doInBackground(Recipient... params) {
            List<Recipient> recipients;
            if (params[0].isGroup()) {
                recipients = SignalDatabase.groups().getGroupMembers(params[0].requireGroupId(), GroupDatabase.MemberSet.FULL_MEMBERS_EXCLUDING_SELF);
            } else {
                recipients = Collections.singletonList(params[0]);
            }
            long startTime = System.currentTimeMillis();
            IdentityRecordList identityRecordList = ApplicationDependencies.getProtocolStore().aci().identities().getIdentityRecords(recipients);
            Log.i(TAG, String.format(Locale.US, "Loaded %d identities in %d ms", recipients.size(), System.currentTimeMillis() - startTime));
            String message = null;
            if (identityRecordList.isUnverified()) {
                message = IdentityUtil.getUnverifiedBannerDescription(context, identityRecordList.getUnverifiedRecipients());
            }
            return new Pair<>(identityRecordList, message);
        }

        @Override
        protected void onPostExecute(@NonNull Pair<IdentityRecordList, String> result) {
            Log.i(TAG, "Got identity records: " + result.first().isUnverified());
            identityRecords = result.first();
            if (result.second() != null) {
                Log.d(TAG, "Replacing banner...");
                unverifiedBannerView.get().display(result.second(), result.first().getUnverifiedRecords(), new UnverifiedClickedListener(), new UnverifiedDismissedListener());
            } else if (unverifiedBannerView.resolved()) {
                Log.d(TAG, "Clearing banner...");
                unverifiedBannerView.get().hide();
            }
            titleView.setVerified(isSecureText && identityRecords.isVerified());
            future.set(true);
        }
    }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, recipient.get());
    return future;
}
Also used : SettableFuture(org.thoughtcrime.securesms.util.concurrent.SettableFuture) Context(android.content.Context) LiveRecipient(org.thoughtcrime.securesms.recipients.LiveRecipient) Recipient(org.thoughtcrime.securesms.recipients.Recipient) SpannableString(android.text.SpannableString) IdentityRecordList(org.thoughtcrime.securesms.database.identity.IdentityRecordList) NonNull(androidx.annotation.NonNull) ArrayList(java.util.ArrayList) IdentityRecordList(org.thoughtcrime.securesms.database.identity.IdentityRecordList) List(java.util.List) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) Pair(org.whispersystems.libsignal.util.Pair)

Example 34 with Pair

use of org.whispersystems.libsignal.util.Pair in project Signal-Android by WhisperSystems.

the class ConversationParentFragment method initializeDraftFromDatabase.

private ListenableFuture<Boolean> initializeDraftFromDatabase() {
    SettableFuture<Boolean> future = new SettableFuture<>();
    final Context context = requireContext().getApplicationContext();
    new AsyncTask<Void, Void, Pair<Drafts, CharSequence>>() {

        @Override
        protected Pair<Drafts, CharSequence> doInBackground(Void... params) {
            DraftDatabase draftDatabase = SignalDatabase.drafts();
            Drafts results = draftDatabase.getDrafts(threadId);
            Draft mentionsDraft = results.getDraftOfType(Draft.MENTION);
            Spannable updatedText = null;
            if (mentionsDraft != null) {
                String text = results.getDraftOfType(Draft.TEXT).getValue();
                List<Mention> mentions = MentionUtil.bodyRangeListToMentions(context, Base64.decodeOrThrow(mentionsDraft.getValue()));
                UpdatedBodyAndMentions updated = MentionUtil.updateBodyAndMentionsWithDisplayNames(context, text, mentions);
                updatedText = new SpannableString(updated.getBody());
                MentionAnnotation.setMentionAnnotations(updatedText, updated.getMentions());
            }
            draftDatabase.clearDrafts(threadId);
            return new Pair<>(results, updatedText);
        }

        @Override
        protected void onPostExecute(Pair<Drafts, CharSequence> draftsWithUpdatedMentions) {
            Drafts drafts = Objects.requireNonNull(draftsWithUpdatedMentions.first());
            CharSequence updatedText = draftsWithUpdatedMentions.second();
            if (drafts.isEmpty()) {
                future.set(false);
                updateToggleButtonState();
                return;
            }
            AtomicInteger draftsRemaining = new AtomicInteger(drafts.size());
            AtomicBoolean success = new AtomicBoolean(false);
            ListenableFuture.Listener<Boolean> listener = new AssertedSuccessListener<Boolean>() {

                @Override
                public void onSuccess(Boolean result) {
                    success.compareAndSet(false, result);
                    if (draftsRemaining.decrementAndGet() <= 0) {
                        future.set(success.get());
                    }
                }
            };
            for (Draft draft : drafts) {
                try {
                    switch(draft.getType()) {
                        case Draft.TEXT:
                            composeText.setText(updatedText == null ? draft.getValue() : updatedText);
                            listener.onSuccess(true);
                            break;
                        case Draft.LOCATION:
                            attachmentManager.setLocation(SignalPlace.deserialize(draft.getValue()), getCurrentMediaConstraints()).addListener(listener);
                            break;
                        case Draft.IMAGE:
                            setMedia(Uri.parse(draft.getValue()), MediaType.IMAGE).addListener(listener);
                            break;
                        case Draft.AUDIO:
                            setMedia(Uri.parse(draft.getValue()), MediaType.AUDIO).addListener(listener);
                            break;
                        case Draft.VIDEO:
                            setMedia(Uri.parse(draft.getValue()), MediaType.VIDEO).addListener(listener);
                            break;
                        case Draft.QUOTE:
                            SettableFuture<Boolean> quoteResult = new SettableFuture<>();
                            new QuoteRestorationTask(draft.getValue(), quoteResult).execute();
                            quoteResult.addListener(listener);
                            break;
                        case Draft.VOICE_NOTE:
                            draftViewModel.setVoiceNoteDraft(recipient.getId(), draft);
                            break;
                    }
                } catch (IOException e) {
                    Log.w(TAG, e);
                }
            }
            updateToggleButtonState();
        }
    }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
    return future;
}
Also used : SettableFuture(org.thoughtcrime.securesms.util.concurrent.SettableFuture) EmojiEventListener(org.thoughtcrime.securesms.components.emoji.EmojiEventListener) OnFocusChangeListener(android.view.View.OnFocusChangeListener) OnKeyListener(android.view.View.OnKeyListener) StickerEventListener(org.thoughtcrime.securesms.stickers.StickerEventListener) AssertedSuccessListener(org.thoughtcrime.securesms.util.concurrent.AssertedSuccessListener) OnKeyboardShownListener(org.thoughtcrime.securesms.components.KeyboardAwareLinearLayout.OnKeyboardShownListener) OnClickListener(android.view.View.OnClickListener) DraftDatabase(org.thoughtcrime.securesms.database.DraftDatabase) SpannableString(android.text.SpannableString) ArrayList(java.util.ArrayList) IdentityRecordList(org.thoughtcrime.securesms.database.identity.IdentityRecordList) List(java.util.List) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) Pair(org.whispersystems.libsignal.util.Pair) Context(android.content.Context) UpdatedBodyAndMentions(org.thoughtcrime.securesms.database.MentionUtil.UpdatedBodyAndMentions) IOException(java.io.IOException) Drafts(org.thoughtcrime.securesms.database.DraftDatabase.Drafts) SpannableString(android.text.SpannableString) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) VoiceNoteDraft(org.thoughtcrime.securesms.components.voice.VoiceNoteDraft) Draft(org.thoughtcrime.securesms.database.DraftDatabase.Draft) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) Spannable(android.text.Spannable)

Example 35 with Pair

use of org.whispersystems.libsignal.util.Pair in project Signal-Android by WhisperSystems.

the class SaveAttachmentTask method doInBackground.

@Override
protected Pair<Integer, String> doInBackground(SaveAttachmentTask.Attachment... attachments) {
    if (attachments == null || attachments.length == 0) {
        throw new AssertionError("must pass in at least one attachment");
    }
    try {
        Context context = contextReference.get();
        String directory = null;
        if (!StorageUtil.canWriteToMediaStore()) {
            return new Pair<>(WRITE_ACCESS_FAILURE, null);
        }
        if (context == null) {
            return new Pair<>(FAILURE, null);
        }
        for (Attachment attachment : attachments) {
            if (attachment != null) {
                directory = saveAttachment(context, attachment);
                if (directory == null) {
                    return new Pair<>(FAILURE, null);
                }
            }
        }
        if (attachments.length > 1) {
            return new Pair<>(SUCCESS, null);
        } else {
            return new Pair<>(SUCCESS, directory);
        }
    } catch (IOException ioe) {
        Log.w(TAG, ioe);
        return new Pair<>(FAILURE, null);
    }
}
Also used : Context(android.content.Context) IOException(java.io.IOException) Pair(org.whispersystems.libsignal.util.Pair)

Aggregations

Pair (org.whispersystems.libsignal.util.Pair)49 NonNull (androidx.annotation.NonNull)26 List (java.util.List)18 LinkedList (java.util.LinkedList)15 Context (android.content.Context)14 Stream (com.annimon.stream.Stream)14 IOException (java.io.IOException)14 Recipient (org.thoughtcrime.securesms.recipients.Recipient)14 RecipientId (org.thoughtcrime.securesms.recipients.RecipientId)14 Nullable (androidx.annotation.Nullable)12 SpannableString (android.text.SpannableString)10 TextUtils (android.text.TextUtils)10 ArrayList (java.util.ArrayList)10 Collections (java.util.Collections)10 Cursor (android.database.Cursor)9 ContentValues (android.content.ContentValues)8 HashSet (java.util.HashSet)8 Locale (java.util.Locale)8 Set (java.util.Set)8 Log (org.signal.core.util.logging.Log)8