From c8238df8ffae640cb0c70503940a1710dc625c2f Mon Sep 17 00:00:00 2001 From: Mikunj Date: Wed, 16 Oct 2019 14:32:10 +1100 Subject: [PATCH 01/14] Update checks to isFromUnkownContact. --- .../securesms/util/AttachmentUtil.java | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/org/thoughtcrime/securesms/util/AttachmentUtil.java b/src/org/thoughtcrime/securesms/util/AttachmentUtil.java index 81c338b370..84ea6cf386 100644 --- a/src/org/thoughtcrime/securesms/util/AttachmentUtil.java +++ b/src/org/thoughtcrime/securesms/util/AttachmentUtil.java @@ -15,6 +15,7 @@ import org.thoughtcrime.securesms.attachments.DatabaseAttachment; import org.thoughtcrime.securesms.database.DatabaseFactory; import org.thoughtcrime.securesms.database.model.MessageRecord; import org.thoughtcrime.securesms.logging.Log; +import org.whispersystems.signalservice.loki.messaging.LokiThreadFriendRequestStatus; import java.util.Collections; import java.util.Set; @@ -106,14 +107,16 @@ public class AttachmentUtil { @WorkerThread private static boolean isFromUnknownContact(@NonNull Context context, @NonNull DatabaseAttachment attachment) { + MessageRecord message; try (Cursor messageCursor = DatabaseFactory.getMmsDatabase(context).getMessage(attachment.getMmsId())) { - final MessageRecord message = DatabaseFactory.getMmsDatabase(context).readerFor(messageCursor).getNext(); - - if (message == null || (!message.getRecipient().isSystemContact() && !message.isOutgoing() && !Util.isOwnNumber(context, message.getRecipient().getAddress()))) { - return true; - } + message = DatabaseFactory.getMmsDatabase(context).readerFor(messageCursor).getNext(); } - return false; + if (message == null) { return true; } + + // check to see if we're friends with the person + long threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdIfExistsFor(message.getRecipient()); + boolean isFriend = threadId >= 0 && DatabaseFactory.getLokiThreadDatabase(context).getFriendRequestStatus(threadId) == LokiThreadFriendRequestStatus.FRIENDS; + return (!isFriend && !message.isOutgoing() && !Util.isOwnNumber(context, message.getRecipient().getAddress())); } } From c6f5adb447c5b48fe9cd8393b78dba3ee11f44f1 Mon Sep 17 00:00:00 2001 From: Mikunj Date: Thu, 17 Oct 2019 10:39:59 +1100 Subject: [PATCH 02/14] Update attachments to use url. --- res/layout/conversation_input_panel.xml | 3 +-- .../securesms/attachments/Attachment.java | 8 +++++++- .../attachments/DatabaseAttachment.java | 4 ++-- .../attachments/MmsNotificationAttachment.java | 2 +- .../attachments/PointerAttachment.java | 10 ++++++---- .../securesms/attachments/UriAttachment.java | 2 +- .../securesms/database/AttachmentDatabase.java | 17 +++++++++++------ .../securesms/database/GroupDatabase.java | 17 ++++++++++++++--- .../securesms/database/MmsDatabase.java | 3 ++- .../database/helpers/SQLCipherOpenHelper.java | 3 +++ .../securesms/jobs/AttachmentDownloadJob.java | 2 +- .../securesms/jobs/AvatarDownloadJob.java | 5 +++-- .../securesms/jobs/PushMediaSendJob.java | 4 ++-- .../securesms/jobs/PushSendJob.java | 2 +- 14 files changed, 55 insertions(+), 27 deletions(-) diff --git a/res/layout/conversation_input_panel.xml b/res/layout/conversation_input_panel.xml index be0ffb8ee1..8c744fa541 100644 --- a/res/layout/conversation_input_panel.xml +++ b/res/layout/conversation_input_panel.xml @@ -108,8 +108,7 @@ android:layout_width="wrap_content" android:layout_height="match_parent" android:clipChildren="false" - android:clipToPadding="false" - android:visibility="gone"> + android:clipToPadding="false"> TYPED_GROUP_PROJECTION = Stream.of(GROUP_PROJECTION).map(columnName -> TABLE_NAME + "." + columnName).toList(); @@ -167,6 +171,7 @@ public class GroupDatabase extends Database { contentValues.put(AVATAR_KEY, avatar.getKey()); contentValues.put(AVATAR_CONTENT_TYPE, avatar.getContentType()); contentValues.put(AVATAR_DIGEST, avatar.getDigest().orNull()); + contentValues.put(AVATAR_URL, avatar.getUrl()); } contentValues.put(AVATAR_RELAY, relay); @@ -194,6 +199,7 @@ public class GroupDatabase extends Database { contentValues.put(AVATAR_CONTENT_TYPE, avatar.getContentType()); contentValues.put(AVATAR_KEY, avatar.getKey()); contentValues.put(AVATAR_DIGEST, avatar.getDigest().orNull()); + contentValues.put(AVATAR_URL, avatar.getUrl()); } databaseHelper.getWritableDatabase().update(TABLE_NAME, contentValues, @@ -344,7 +350,8 @@ public class GroupDatabase extends Database { cursor.getString(cursor.getColumnIndexOrThrow(AVATAR_RELAY)), cursor.getInt(cursor.getColumnIndexOrThrow(ACTIVE)) == 1, cursor.getBlob(cursor.getColumnIndexOrThrow(AVATAR_DIGEST)), - cursor.getInt(cursor.getColumnIndexOrThrow(MMS)) == 1); + cursor.getInt(cursor.getColumnIndexOrThrow(MMS)) == 1, + cursor.getString(cursor.getColumnIndexOrThrow(AVATAR_URL))); } @Override @@ -367,10 +374,11 @@ public class GroupDatabase extends Database { private final String relay; private final boolean active; private final boolean mms; + private final String url; public GroupRecord(String id, String title, String members, byte[] avatar, long avatarId, byte[] avatarKey, String avatarContentType, - String relay, boolean active, byte[] avatarDigest, boolean mms) + String relay, boolean active, byte[] avatarDigest, boolean mms, String url) { this.id = id; this.title = title; @@ -382,6 +390,7 @@ public class GroupDatabase extends Database { this.relay = relay; this.active = active; this.mms = mms; + this.url = url; if (!TextUtils.isEmpty(members)) this.members = Address.fromSerializedList(members, ','); else this.members = new LinkedList<>(); @@ -438,5 +447,7 @@ public class GroupDatabase extends Database { public boolean isMms() { return mms; } + + public String getUrl() { return url; } } } diff --git a/src/org/thoughtcrime/securesms/database/MmsDatabase.java b/src/org/thoughtcrime/securesms/database/MmsDatabase.java index 6fea8f244e..5ce830b3b4 100644 --- a/src/org/thoughtcrime/securesms/database/MmsDatabase.java +++ b/src/org/thoughtcrime/securesms/database/MmsDatabase.java @@ -778,7 +778,8 @@ public class MmsDatabase extends MessagingDatabase { databaseAttachment.getHeight(), databaseAttachment.isQuote(), databaseAttachment.getCaption(), - databaseAttachment.getSticker())); + databaseAttachment.getSticker(), + databaseAttachment.getUrl())); } return insertMediaMessage(request.getBody(), diff --git a/src/org/thoughtcrime/securesms/database/helpers/SQLCipherOpenHelper.java b/src/org/thoughtcrime/securesms/database/helpers/SQLCipherOpenHelper.java index 28122e956c..9216a2314b 100644 --- a/src/org/thoughtcrime/securesms/database/helpers/SQLCipherOpenHelper.java +++ b/src/org/thoughtcrime/securesms/database/helpers/SQLCipherOpenHelper.java @@ -499,6 +499,9 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper { if (oldVersion < lokiV3) { db.execSQL(LokiAPIDatabase.getCreatePairingAuthorisationTableCommand()); db.execSQL(LokiThreadDatabase.getCreatePublicChatTableCommand()); + + db.execSQL("ALTER TABLE groups ADD COLUMN avatar_url TEXT"); + db.execSQL("ALTER TABLE part ADD COLUMN url TEXT"); } db.setTransactionSuccessful(); diff --git a/src/org/thoughtcrime/securesms/jobs/AttachmentDownloadJob.java b/src/org/thoughtcrime/securesms/jobs/AttachmentDownloadJob.java index 947ed11250..4734ee2e5c 100644 --- a/src/org/thoughtcrime/securesms/jobs/AttachmentDownloadJob.java +++ b/src/org/thoughtcrime/securesms/jobs/AttachmentDownloadJob.java @@ -213,7 +213,7 @@ public class AttachmentDownloadJob extends BaseJob implements InjectableType { Optional.fromNullable(attachment.getDigest()), Optional.fromNullable(attachment.getFileName()), attachment.isVoiceNote(), - Optional.absent()); + Optional.absent(), attachment.getUrl()); } catch (IOException | ArithmeticException e) { Log.w(TAG, e); throw new InvalidPartException(e); diff --git a/src/org/thoughtcrime/securesms/jobs/AvatarDownloadJob.java b/src/org/thoughtcrime/securesms/jobs/AvatarDownloadJob.java index b97a410dbd..3536051086 100644 --- a/src/org/thoughtcrime/securesms/jobs/AvatarDownloadJob.java +++ b/src/org/thoughtcrime/securesms/jobs/AvatarDownloadJob.java @@ -80,8 +80,9 @@ public class AvatarDownloadJob extends BaseJob implements InjectableType { String relay = record.get().getRelay(); Optional digest = Optional.fromNullable(record.get().getAvatarDigest()); Optional fileName = Optional.absent(); + String url = record.get().getUrl(); - if (avatarId == -1 || key == null) { + if (avatarId == -1 || key == null || url.isEmpty()) { return; } @@ -92,7 +93,7 @@ public class AvatarDownloadJob extends BaseJob implements InjectableType { attachment = File.createTempFile("avatar", "tmp", context.getCacheDir()); attachment.deleteOnExit(); - SignalServiceAttachmentPointer pointer = new SignalServiceAttachmentPointer(avatarId, contentType, key, Optional.of(0), Optional.absent(), 0, 0, digest, fileName, false, Optional.absent()); + SignalServiceAttachmentPointer pointer = new SignalServiceAttachmentPointer(avatarId, contentType, key, Optional.of(0), Optional.absent(), 0, 0, digest, fileName, false, Optional.absent(), url); InputStream inputStream = receiver.retrieveAttachment(pointer, attachment, MAX_AVATAR_SIZE); Bitmap avatar = BitmapUtil.createScaledBitmap(context, new AttachmentModel(attachment, key, 0, digest), 500, 500); diff --git a/src/org/thoughtcrime/securesms/jobs/PushMediaSendJob.java b/src/org/thoughtcrime/securesms/jobs/PushMediaSendJob.java index 478557be40..1b3de7a276 100644 --- a/src/org/thoughtcrime/securesms/jobs/PushMediaSendJob.java +++ b/src/org/thoughtcrime/securesms/jobs/PushMediaSendJob.java @@ -105,8 +105,8 @@ public class PushMediaSendJob extends PushSendJob implements InjectableType { List attachments = new LinkedList<>(); // Loki - For now all attachments are re-fetched by the receiver - // attachments.addAll(message.getAttachments()); - // attachments.addAll(Stream.of(message.getLinkPreviews()).filter(p -> p.getThumbnail().isPresent()).map(p -> p.getThumbnail().get()).toList()); + attachments.addAll(message.getAttachments()); + attachments.addAll(Stream.of(message.getLinkPreviews()).filter(p -> p.getThumbnail().isPresent()).map(p -> p.getThumbnail().get()).toList()); attachments.addAll(Stream.of(message.getSharedContacts()).filter(c -> c.getAvatar() != null).map(c -> c.getAvatar().getAttachment()).withoutNulls().toList()); List attachmentJobs = Stream.of(attachments).map(a -> new AttachmentUploadJob(((DatabaseAttachment) a).getAttachmentId())).toList(); diff --git a/src/org/thoughtcrime/securesms/jobs/PushSendJob.java b/src/org/thoughtcrime/securesms/jobs/PushSendJob.java index e64db9029a..aaedf8f25a 100644 --- a/src/org/thoughtcrime/securesms/jobs/PushSendJob.java +++ b/src/org/thoughtcrime/securesms/jobs/PushSendJob.java @@ -172,7 +172,7 @@ public abstract class PushSendJob extends SendJob { Optional.fromNullable(attachment.getDigest()), Optional.fromNullable(attachment.getFileName()), attachment.isVoiceNote(), - Optional.fromNullable(attachment.getCaption())); + Optional.fromNullable(attachment.getCaption()), attachment.getUrl()); } catch (IOException | ArithmeticException e) { Log.w(TAG, e); return null; From fd9f1b712fcc99833c16a5efb921bc39e26c2985 Mon Sep 17 00:00:00 2001 From: Mikunj Date: Fri, 18 Oct 2019 12:40:41 +1100 Subject: [PATCH 03/14] Get attachment logic to work. --- res/layout/attachment_type_selector.xml | 168 ++++++++++-------- res/menu/conversation.xml | 4 +- .../conversation/ConversationActivity.java | 4 +- .../conversation/ConversationItem.java | 2 +- .../securesms/database/MmsSmsDatabase.java | 2 +- .../securesms/jobs/PushDecryptJob.java | 5 + .../securesms/jobs/RetrieveProfileJob.java | 3 + .../securesms/sms/MessageSender.java | 37 ++-- 8 files changed, 115 insertions(+), 110 deletions(-) diff --git a/res/layout/attachment_type_selector.xml b/res/layout/attachment_type_selector.xml index 7f96eaae2c..31bdb96240 100644 --- a/res/layout/attachment_type_selector.xml +++ b/res/layout/attachment_type_selector.xml @@ -27,7 +27,7 @@ android:layout_marginStart="16dp" android:layout_marginEnd="16dp" android:layout_marginTop="16dp" - android:weightSum="4"> + android:weightSum="2"> + android:layout_height="wrap_content" + android:layout_weight="1" + android:gravity="center" + android:orientation="vertical"> + android:id="@+id/camera_button" + android:layout_width="53dp" + android:layout_height="53dp" + android:src="@drawable/ic_camera_white_24dp" + android:scaleType="center" + android:contentDescription="@string/attachment_type_selector__camera_description" + app:circleColor="@color/green_400"/> + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:gravity="center" + style="@style/AttachmentTypeLabel" + android:text="@string/attachment_type_selector__camera"/> - + + android:id="@+id/audio_button" + android:layout_width="53dp" + android:layout_height="53dp" + android:contentDescription="@string/attachment_type_selector__audio_description" + android:scaleType="center" + android:src="@drawable/ic_headset_white_24dp" + app:circleColor="@color/orange_400" /> + + - + + + + + + + @@ -102,7 +132,8 @@ android:layout_height="wrap_content" android:gravity="center" android:orientation="vertical" - android:layout_weight="1"> + android:layout_weight="1" + android:visibility="gone"> + android:weightSum="2"> - - - - - - - - - + - - + android:id="@+id/location_button" + android:layout_width="53dp" + android:layout_height="53dp" + android:contentDescription="@string/attachment_type_selector__location_description" + android:scaleType="center" + android:src="@drawable/ic_location_on_white_24dp" + app:circleColor="@color/blue_grey_400" /> + + @@ -223,7 +233,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" style="@style/AttachmentTypeLabel" - android:text=" "/> + android:text=""/> diff --git a/res/menu/conversation.xml b/res/menu/conversation.xml index 7213e498c3..cd33628267 100644 --- a/res/menu/conversation.xml +++ b/res/menu/conversation.xml @@ -2,10 +2,10 @@ - diff --git a/src/org/thoughtcrime/securesms/conversation/ConversationActivity.java b/src/org/thoughtcrime/securesms/conversation/ConversationActivity.java index 39412b48ee..d5903cce96 100644 --- a/src/org/thoughtcrime/securesms/conversation/ConversationActivity.java +++ b/src/org/thoughtcrime/securesms/conversation/ConversationActivity.java @@ -792,7 +792,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity switch (item.getItemId()) { case R.id.menu_call_secure: handleDial(getRecipient(), true); return true; case R.id.menu_call_insecure: handleDial(getRecipient(), false); return true; - // case R.id.menu_view_media: handleViewMedia(); return true; + case R.id.menu_view_media: handleViewMedia(); return true; case R.id.menu_add_shortcut: handleAddShortcut(); return true; case R.id.menu_search: handleSearch(); return true; case R.id.menu_add_to_contacts: handleAddToContacts(); return true; @@ -2408,7 +2408,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity } if (composeText.getText().length() == 0 && !attachmentManager.isAttachmentPresent()) { - buttonToggle.display(sendButton); + buttonToggle.display(attachButton); quickAttachmentToggle.show(); inlineAttachmentToggle.hide(); } else { diff --git a/src/org/thoughtcrime/securesms/conversation/ConversationItem.java b/src/org/thoughtcrime/securesms/conversation/ConversationItem.java index 57fbe13391..7e66fbbcd3 100644 --- a/src/org/thoughtcrime/securesms/conversation/ConversationItem.java +++ b/src/org/thoughtcrime/securesms/conversation/ConversationItem.java @@ -473,7 +473,7 @@ public class ConversationItem extends LinearLayout if (isCaptionlessMms(messageRecord)) { bodyText.setVisibility(View.GONE); - } else { ; + } else { Spannable text = MentionUtilities.highlightMentions(linkifyMessageBody(messageRecord.getDisplayBody(context), batchSelected.isEmpty()), messageRecord.isOutgoing(), messageRecord.getThreadId(), context); text = SearchUtil.getHighlightedSpan(locale, () -> new BackgroundColorSpan(Color.YELLOW), text, searchQuery); text = SearchUtil.getHighlightedSpan(locale, () -> new ForegroundColorSpan(Color.BLACK), text, searchQuery); diff --git a/src/org/thoughtcrime/securesms/database/MmsSmsDatabase.java b/src/org/thoughtcrime/securesms/database/MmsSmsDatabase.java index a2c4da21ff..bfe549eb29 100644 --- a/src/org/thoughtcrime/securesms/database/MmsSmsDatabase.java +++ b/src/org/thoughtcrime/securesms/database/MmsSmsDatabase.java @@ -98,7 +98,7 @@ public class MmsSmsDatabase extends Database { public Cursor getConversation(long threadId, long offset, long limit) { String order = MmsSmsColumns.NORMALIZED_DATE_RECEIVED + " DESC"; - String selection = MmsSmsColumns.THREAD_ID + " = " + threadId + " AND LENGTH(" + MmsSmsColumns.BODY + ") > 0"; + String selection = MmsSmsColumns.THREAD_ID + " = " + threadId; String limitStr = limit > 0 || offset > 0 ? offset + ", " + limit : null; Cursor cursor = queryTables(PROJECTION, selection, order, limitStr); diff --git a/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java b/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java index 0007d8c87c..3abcbcdaea 100644 --- a/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java +++ b/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java @@ -795,6 +795,11 @@ public class PushDecryptJob extends BaseJob implements InjectableType { MmsDatabase database = DatabaseFactory.getMmsDatabase(context); database.beginTransaction(); + // Ignore message if it has no body and no attachments or anything + if (mediaMessage.getBody().isEmpty() && mediaMessage.getAttachments().isEmpty() && mediaMessage.getSharedContacts().isEmpty() && mediaMessage.getLinkPreviews().isEmpty()) { + return; + } + Optional insertResult; try { diff --git a/src/org/thoughtcrime/securesms/jobs/RetrieveProfileJob.java b/src/org/thoughtcrime/securesms/jobs/RetrieveProfileJob.java index e7effa2eb5..43d3fdde7d 100644 --- a/src/org/thoughtcrime/securesms/jobs/RetrieveProfileJob.java +++ b/src/org/thoughtcrime/securesms/jobs/RetrieveProfileJob.java @@ -77,12 +77,15 @@ public class RetrieveProfileJob extends BaseJob implements InjectableType { @Override public void onRun() throws IOException, InvalidKeyException { + // Loki - Disable retrieve profile + /* try { if (recipient.isGroupRecipient()) handleGroupRecipient(recipient); else handleIndividualRecipient(recipient); } catch (InvalidNumberException e) { Log.w(TAG, e); } + */ } @Override diff --git a/src/org/thoughtcrime/securesms/sms/MessageSender.java b/src/org/thoughtcrime/securesms/sms/MessageSender.java index d6cb29279d..195db0e6d9 100644 --- a/src/org/thoughtcrime/securesms/sms/MessageSender.java +++ b/src/org/thoughtcrime/securesms/sms/MessageSender.java @@ -58,6 +58,7 @@ import org.whispersystems.signalservice.loki.api.LokiStorageAPI; import org.whispersystems.signalservice.loki.messaging.LokiMessageFriendRequestStatus; import java.io.IOException; +import java.util.function.Function; import kotlin.Unit; @@ -117,32 +118,18 @@ public class MessageSender { // Loki - Turn into a GIF message if possible if (message.getLinkPreviews().isEmpty() && message.getAttachments().isEmpty() && LinkPreviewUtil.isWhitelistedMediaUrl(message.getBody())) { new LinkPreviewRepository(context).fetchGIF(context, message.getBody(), attachmentOrNull -> Util.runOnMain(() -> { - if (attachmentOrNull.isPresent()) { - Attachment attachment = attachmentOrNull.get(); - try { - message.getAttachments().add(attachment); - long messageID = database.insertMessageOutbox(message, allocatedThreadId, forceSms, insertListener); - // Loki - Set the message's friend request status as soon as it has hit the database - if (message.isFriendRequest) { - DatabaseFactory.getLokiMessageDatabase(context).setFriendRequestStatus(messageID, LokiMessageFriendRequestStatus.REQUEST_SENDING); - } - sendMediaMessage(context, recipient, forceSms, messageID, message.getExpiresIn()); - } catch (Exception e) { - Log.w(TAG, e); - // TODO: Handle - } - } else { - try { - long messageID = database.insertMessageOutbox(message, allocatedThreadId, forceSms, insertListener); - // Loki - Set the message's friend request status as soon as it has hit the database - if (message.isFriendRequest) { - DatabaseFactory.getLokiMessageDatabase(context).setFriendRequestStatus(messageID, LokiMessageFriendRequestStatus.REQUEST_SENDING); - } - sendMediaMessage(context, recipient, forceSms, messageID, message.getExpiresIn()); - } catch (MmsException e) { - Log.w(TAG, e); - // TODO: Handle + Attachment attachment = attachmentOrNull.orNull(); + try { + if (attachment != null) { message.getAttachments().add(attachment); } + long messageID = database.insertMessageOutbox(message, allocatedThreadId, forceSms, insertListener); + // Loki - Set the message's friend request status as soon as it has hit the database + if (message.isFriendRequest) { + DatabaseFactory.getLokiMessageDatabase(context).setFriendRequestStatus(messageID, LokiMessageFriendRequestStatus.REQUEST_SENDING); } + sendMediaMessage(context, recipient, forceSms, messageID, message.getExpiresIn()); + } catch (Exception e) { + Log.w(TAG, e); + // TODO: Handle } })); } else { From 8d6094ecd62e47ec69d3399e0344109ef0a67295 Mon Sep 17 00:00:00 2001 From: Mikunj Date: Fri, 18 Oct 2019 15:16:41 +1100 Subject: [PATCH 04/14] Fix crash when viewing media --- .../thoughtcrime/securesms/database/AttachmentDatabase.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/org/thoughtcrime/securesms/database/AttachmentDatabase.java b/src/org/thoughtcrime/securesms/database/AttachmentDatabase.java index 2beec07057..918ffbd9d1 100644 --- a/src/org/thoughtcrime/securesms/database/AttachmentDatabase.java +++ b/src/org/thoughtcrime/securesms/database/AttachmentDatabase.java @@ -659,6 +659,7 @@ public class AttachmentDatabase extends Database { return result; } else { + int urlIndex = cursor.getColumnIndex(URL); return Collections.singletonList(new DatabaseAttachment(new AttachmentId(cursor.getLong(cursor.getColumnIndexOrThrow(ROW_ID)), cursor.getLong(cursor.getColumnIndexOrThrow(UNIQUE_ID))), cursor.getLong(cursor.getColumnIndexOrThrow(MMS_ID)), @@ -683,7 +684,7 @@ public class AttachmentDatabase extends Database { cursor.getString(cursor.getColumnIndexOrThrow(STICKER_PACK_KEY)), cursor.getInt(cursor.getColumnIndexOrThrow(STICKER_ID))) : null, - cursor.getString(cursor.getColumnIndexOrThrow(URL)))); + urlIndex > 0 ? cursor.getString(urlIndex) : "")); } } catch (JSONException e) { throw new AssertionError(e); From b12e6b838caa64c1689df02392db3179d6892737 Mon Sep 17 00:00:00 2001 From: Mikunj Date: Fri, 18 Oct 2019 16:12:49 +1100 Subject: [PATCH 05/14] Disable attachments on non-friends. --- res/layout/conversation_input_panel.xml | 3 ++- .../securesms/conversation/ConversationActivity.java | 10 ++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/res/layout/conversation_input_panel.xml b/res/layout/conversation_input_panel.xml index 8c744fa541..6812e6c775 100644 --- a/res/layout/conversation_input_panel.xml +++ b/res/layout/conversation_input_panel.xml @@ -127,7 +127,8 @@ android:paddingStart="6dp" android:paddingEnd="6dp" android:background="?selectableItemBackgroundBorderless" - android:contentDescription="@string/conversation_activity__quick_attachment_drawer_toggle_camera_description" /> + android:contentDescription="@string/conversation_activity__quick_attachment_drawer_toggle_camera_description" + android:visibility="gone"/> Date: Mon, 21 Oct 2019 10:52:53 +1100 Subject: [PATCH 06/14] Update attachments for public group chats. --- res/layout/conversation_input_panel.xml | 9 ++-- .../securesms/jobs/AttachmentDownloadJob.java | 15 +++++- .../securesms/jobs/AttachmentUploadJob.java | 20 +++++--- .../securesms/jobs/PushGroupSendJob.java | 7 ++- .../securesms/jobs/PushMediaSendJob.java | 2 +- .../securesms/loki/LokiPublicChatPoller.kt | 47 +++++++++++++------ .../securesms/util/AttachmentUtil.java | 5 ++ 7 files changed, 73 insertions(+), 32 deletions(-) diff --git a/res/layout/conversation_input_panel.xml b/res/layout/conversation_input_panel.xml index 6812e6c775..54f8563e54 100644 --- a/res/layout/conversation_input_panel.xml +++ b/res/layout/conversation_input_panel.xml @@ -127,8 +127,7 @@ android:paddingStart="6dp" android:paddingEnd="6dp" android:background="?selectableItemBackgroundBorderless" - android:contentDescription="@string/conversation_activity__quick_attachment_drawer_toggle_camera_description" - android:visibility="gone"/> + android:contentDescription="@string/conversation_activity__quick_attachment_drawer_toggle_camera_description" /> + android:clipToPadding="false" + android:visibility="gone"> @@ -148,8 +148,7 @@ android:id="@+id/inline_attachment_container" android:layout_width="wrap_content" android:layout_height="match_parent" - android:layout_gravity="right|end" - android:visibility="gone"> + android:layout_gravity="right|end"> { @Override public @NonNull AttachmentUploadJob create(@NonNull Parameters parameters, @NonNull org.thoughtcrime.securesms.jobmanager.Data data) { - return new AttachmentUploadJob(parameters, new AttachmentId(data.getLong(KEY_ROW_ID), data.getLong(KEY_UNIQUE_ID))); + return new AttachmentUploadJob(parameters, new AttachmentId(data.getLong(KEY_ROW_ID), data.getLong(KEY_UNIQUE_ID)), Address.fromSerialized(data.getString(KEY_DESTINATION))); } } } diff --git a/src/org/thoughtcrime/securesms/jobs/PushGroupSendJob.java b/src/org/thoughtcrime/securesms/jobs/PushGroupSendJob.java index be4dd9ed4e..d5d4fa6c99 100644 --- a/src/org/thoughtcrime/securesms/jobs/PushGroupSendJob.java +++ b/src/org/thoughtcrime/securesms/jobs/PushGroupSendJob.java @@ -96,12 +96,11 @@ public class PushGroupSendJob extends PushSendJob implements InjectableType { OutgoingMediaMessage message = database.getOutgoingMessage(messageId); List attachments = new LinkedList<>(); - // Loki - For now all attachments are re-fetched by the receiver - // attachments.addAll(message.getAttachments()); - // attachments.addAll(Stream.of(message.getLinkPreviews()).filter(p -> p.getThumbnail().isPresent()).map(p -> p.getThumbnail().get()).toList()); + attachments.addAll(message.getAttachments()); + attachments.addAll(Stream.of(message.getLinkPreviews()).filter(p -> p.getThumbnail().isPresent()).map(p -> p.getThumbnail().get()).toList()); attachments.addAll(Stream.of(message.getSharedContacts()).filter(c -> c.getAvatar() != null).map(c -> c.getAvatar().getAttachment()).withoutNulls().toList()); - List attachmentJobs = Stream.of(attachments).map(a -> new AttachmentUploadJob(((DatabaseAttachment) a).getAttachmentId())).toList(); + List attachmentJobs = Stream.of(attachments).map(a -> new AttachmentUploadJob(((DatabaseAttachment) a).getAttachmentId(), destination)).toList(); if (attachmentJobs.isEmpty()) { jobManager.add(new PushGroupSendJob(messageId, destination, filterAddress)); diff --git a/src/org/thoughtcrime/securesms/jobs/PushMediaSendJob.java b/src/org/thoughtcrime/securesms/jobs/PushMediaSendJob.java index 1b3de7a276..bcfe4b9de0 100644 --- a/src/org/thoughtcrime/securesms/jobs/PushMediaSendJob.java +++ b/src/org/thoughtcrime/securesms/jobs/PushMediaSendJob.java @@ -109,7 +109,7 @@ public class PushMediaSendJob extends PushSendJob implements InjectableType { attachments.addAll(Stream.of(message.getLinkPreviews()).filter(p -> p.getThumbnail().isPresent()).map(p -> p.getThumbnail().get()).toList()); attachments.addAll(Stream.of(message.getSharedContacts()).filter(c -> c.getAvatar() != null).map(c -> c.getAvatar().getAttachment()).withoutNulls().toList()); - List attachmentJobs = Stream.of(attachments).map(a -> new AttachmentUploadJob(((DatabaseAttachment) a).getAttachmentId())).toList(); + List attachmentJobs = Stream.of(attachments).map(a -> new AttachmentUploadJob(((DatabaseAttachment) a).getAttachmentId(), destination)).toList(); if (attachmentJobs.isEmpty()) { jobManager.add(new PushMediaSendJob(templateMessageId, messageId, destination, isFriendRequest, customFriendRequestMessage)); diff --git a/src/org/thoughtcrime/securesms/loki/LokiPublicChatPoller.kt b/src/org/thoughtcrime/securesms/loki/LokiPublicChatPoller.kt index 2530ae021c..98e6e8d1dd 100644 --- a/src/org/thoughtcrime/securesms/loki/LokiPublicChatPoller.kt +++ b/src/org/thoughtcrime/securesms/loki/LokiPublicChatPoller.kt @@ -17,10 +17,9 @@ import org.thoughtcrime.securesms.util.GroupUtil import org.thoughtcrime.securesms.util.TextSecurePreferences import org.thoughtcrime.securesms.util.Util import org.whispersystems.libsignal.util.guava.Optional -import org.whispersystems.signalservice.api.messages.SignalServiceContent -import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage -import org.whispersystems.signalservice.api.messages.SignalServiceGroup +import org.whispersystems.signalservice.api.messages.* import org.whispersystems.signalservice.api.push.SignalServiceAddress +import org.whispersystems.signalservice.internal.push.SignalServiceProtos import org.whispersystems.signalservice.loki.api.LokiPublicChat import org.whispersystems.signalservice.loki.api.LokiPublicChatAPI import org.whispersystems.signalservice.loki.api.LokiPublicChatMessage @@ -96,21 +95,35 @@ class LokiPublicChatPoller(private val context: Context, private val group: Loki private fun pollForNewMessages() { fun processIncomingMessage(message: LokiPublicChatMessage) { val id = group.id.toByteArray() - val x1 = SignalServiceGroup(SignalServiceGroup.Type.UPDATE, id, null, null, null) - val quote: SignalServiceDataMessage.Quote? - if (message.quote != null) { - quote = SignalServiceDataMessage.Quote(message.quote!!.quotedMessageTimestamp, SignalServiceAddress(message.quote!!.quoteeHexEncodedPublicKey), message.quote!!.quotedMessageBody, listOf()) + val serviceGroup = SignalServiceGroup(SignalServiceGroup.Type.UPDATE, id, null, null, null) + val quote = if (message.quote != null) { + SignalServiceDataMessage.Quote(message.quote!!.quotedMessageTimestamp, SignalServiceAddress(message.quote!!.quoteeHexEncodedPublicKey), message.quote!!.quotedMessageBody, listOf()) } else { - quote = null + null + } + val attachments = message.attachments.map { attachment -> + SignalServiceAttachmentPointer( + attachment.serverID, + attachment.contentType, + ByteArray(0), + Optional.of(attachment.size), + Optional.absent(), + attachment.width, attachment.height, + Optional.absent(), + Optional.of(attachment.fileName), + false, + Optional.fromNullable(attachment.caption), + attachment.url) } - val x2 = SignalServiceDataMessage(message.timestamp, x1, listOf(), message.body, false, 0, false, null, false, quote, null, null, null) - val x3 = SignalServiceContent(x2, message.hexEncodedPublicKey, SignalServiceAddress.DEFAULT_DEVICE_ID, message.timestamp, false) + val body = if (message.body == message.timestamp.toString()) "" else message.body // Workaround for the fact that the back-end doesn't accept messages without a body + val serviceDataMessage = SignalServiceDataMessage(message.timestamp, serviceGroup, attachments, body, false, 0, false, null, false, quote, null, null, null) + val serviceContent = SignalServiceContent(serviceDataMessage, message.hexEncodedPublicKey, SignalServiceAddress.DEFAULT_DEVICE_ID, message.timestamp, false) val senderDisplayName = "${message.displayName} (...${message.hexEncodedPublicKey.takeLast(8)})" DatabaseFactory.getLokiUserDatabase(context).setServerDisplayName(group.id, message.hexEncodedPublicKey, senderDisplayName) - if (quote != null) { - PushDecryptJob(context).handleMediaMessage(x3, x2, Optional.absent(), Optional.of(message.serverID)) + if (quote != null || attachments.count() > 0) { + PushDecryptJob(context).handleMediaMessage(serviceContent, serviceDataMessage, Optional.absent(), Optional.of(message.serverID)) } else { - PushDecryptJob(context).handleTextMessage(x3, x2, Optional.absent(), Optional.of(message.serverID)) + PushDecryptJob(context).handleTextMessage(serviceContent, serviceDataMessage, Optional.absent(), Optional.of(message.serverID)) } } fun processOutgoingMessage(message: LokiPublicChatMessage) { @@ -118,6 +131,10 @@ class LokiPublicChatPoller(private val context: Context, private val group: Loki val lokiMessageDatabase = DatabaseFactory.getLokiMessageDatabase(context) val isDuplicate = lokiMessageDatabase.getMessageID(messageServerID) != null if (isDuplicate) { return } + + // Ignore empty messages with no attachments or quotes + if (message.body.isEmpty() && message.attachments.isEmpty() && message.quote == null) { return } + val id = group.id.toByteArray() val mmsDatabase = DatabaseFactory.getMmsDatabase(context) val recipient = Recipient.from(context, Address.fromSerialized(GroupUtil.getEncodedId(id, false)), false) @@ -127,7 +144,9 @@ class LokiPublicChatPoller(private val context: Context, private val group: Loki } else { quote = null } - val signalMessage = OutgoingMediaMessage(recipient, message.body, listOf(), message.timestamp, 0, 0, + // TODO: Handle attachments correctly for our previous messages + val body = if (message.body == message.timestamp.toString()) "" else message.body // Workaround for the fact that the back-end doesn't accept messages without a body + val signalMessage = OutgoingMediaMessage(recipient, body, listOf(), message.timestamp, 0, 0, ThreadDatabase.DistributionTypes.DEFAULT, quote, listOf(), listOf(), listOf(), listOf()) val threadID = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipient) fun finalize() { diff --git a/src/org/thoughtcrime/securesms/util/AttachmentUtil.java b/src/org/thoughtcrime/securesms/util/AttachmentUtil.java index 84ea6cf386..5e2f88b978 100644 --- a/src/org/thoughtcrime/securesms/util/AttachmentUtil.java +++ b/src/org/thoughtcrime/securesms/util/AttachmentUtil.java @@ -114,9 +114,14 @@ public class AttachmentUtil { if (message == null) { return true; } + // TODO: Fix this so we can detect whether attachment is from a public group or not + return false; + + /* // check to see if we're friends with the person long threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdIfExistsFor(message.getRecipient()); boolean isFriend = threadId >= 0 && DatabaseFactory.getLokiThreadDatabase(context).getFriendRequestStatus(threadId) == LokiThreadFriendRequestStatus.FRIENDS; return (!isFriend && !message.isOutgoing() && !Util.isOwnNumber(context, message.getRecipient().getAddress())); + */ } } From a978253e006742f792cea0ad7ae8d6e8e8ad689f Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Mon, 21 Oct 2019 15:26:57 +1100 Subject: [PATCH 07/14] Fix indentation --- res/layout/attachment_type_selector.xml | 221 +++++++++--------- .../securesms/loki/LokiPublicChatPoller.kt | 9 +- 2 files changed, 120 insertions(+), 110 deletions(-) diff --git a/res/layout/attachment_type_selector.xml b/res/layout/attachment_type_selector.xml index 31bdb96240..212cbf9daf 100644 --- a/res/layout/attachment_type_selector.xml +++ b/res/layout/attachment_type_selector.xml @@ -1,54 +1,59 @@ - - - - - - + + + + + - - + android:id="@+id/recent_photos" + android:layout_width="match_parent" + android:layout_height="90dp" + android:padding="4dp"/> + + - + + android:id="@+id/gallery_button" + android:layout_width="53dp" + android:layout_height="53dp" + android:src="@drawable/ic_image_white_24dp" + android:scaleType="center" + android:contentDescription="@string/attachment_type_selector__gallery_description" + app:circleColor="@color/purple_400"/> - + @@ -128,40 +133,43 @@ - + + android:id="@+id/contact_button" + android:layout_width="53dp" + android:layout_height="53dp" + android:src="@drawable/ic_person_white_24dp" + android:scaleType="center" + android:contentDescription="@string/attachment_type_selector__contact_description" + app:circleColor="@color/blue_400"/> - + - + - + + android:id="@+id/giphy_button" + android:layout_width="53dp" + android:layout_height="53dp" + android:src="@drawable/ic_gif_white_24dp" + android:scaleType="center" + android:contentDescription="@string/attachment_type_selector__gif_description" + app:circleColor="@color/cyan_400"/> - + - + + android:id="@+id/close_button" + android:layout_width="53dp" + android:layout_height="53dp" + android:src="@drawable/ic_keyboard_arrow_down_white_24dp" + android:scaleType="center" + android:contentDescription="@string/attachment_type_selector__drawer_description" + app:circleColor="@color/gray50"/> - + - diff --git a/src/org/thoughtcrime/securesms/loki/LokiPublicChatPoller.kt b/src/org/thoughtcrime/securesms/loki/LokiPublicChatPoller.kt index 98e6e8d1dd..5cd1b4c95c 100644 --- a/src/org/thoughtcrime/securesms/loki/LokiPublicChatPoller.kt +++ b/src/org/thoughtcrime/securesms/loki/LokiPublicChatPoller.kt @@ -17,9 +17,11 @@ import org.thoughtcrime.securesms.util.GroupUtil import org.thoughtcrime.securesms.util.TextSecurePreferences import org.thoughtcrime.securesms.util.Util import org.whispersystems.libsignal.util.guava.Optional -import org.whispersystems.signalservice.api.messages.* +import org.whispersystems.signalservice.api.messages.SignalServiceAttachmentPointer +import org.whispersystems.signalservice.api.messages.SignalServiceContent +import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage +import org.whispersystems.signalservice.api.messages.SignalServiceGroup import org.whispersystems.signalservice.api.push.SignalServiceAddress -import org.whispersystems.signalservice.internal.push.SignalServiceProtos import org.whispersystems.signalservice.loki.api.LokiPublicChat import org.whispersystems.signalservice.loki.api.LokiPublicChatAPI import org.whispersystems.signalservice.loki.api.LokiPublicChatMessage @@ -131,10 +133,7 @@ class LokiPublicChatPoller(private val context: Context, private val group: Loki val lokiMessageDatabase = DatabaseFactory.getLokiMessageDatabase(context) val isDuplicate = lokiMessageDatabase.getMessageID(messageServerID) != null if (isDuplicate) { return } - - // Ignore empty messages with no attachments or quotes if (message.body.isEmpty() && message.attachments.isEmpty() && message.quote == null) { return } - val id = group.id.toByteArray() val mmsDatabase = DatabaseFactory.getMmsDatabase(context) val recipient = Recipient.from(context, Address.fromSerialized(GroupUtil.getEncodedId(id, false)), false) From f7e01688b0f87d708b3be49f841b24c417fbb207 Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Mon, 21 Oct 2019 15:35:52 +1100 Subject: [PATCH 08/14] Disable device linking for now --- res/layout/activity_seed.xml | 3 ++- res/xml/preferences.xml | 2 +- .../securesms/ApplicationPreferencesActivity.java | 4 ++++ src/org/thoughtcrime/securesms/loki/SeedActivity.kt | 3 ++- 4 files changed, 9 insertions(+), 3 deletions(-) diff --git a/res/layout/activity_seed.xml b/res/layout/activity_seed.xml index 30e7062e11..cd79c01125 100644 --- a/res/layout/activity_seed.xml +++ b/res/layout/activity_seed.xml @@ -123,7 +123,8 @@ android:layout_height="50dp" android:background="@color/transparent" android:textColor="@color/signal_primary" - android:text="@string/activity_key_pair_toggle_mode_button_title_3" + android:text="Link Device (Coming Soon)" + android:alpha="0.24" android:elevation="0dp" android:stateListAnimator="@null" /> diff --git a/res/xml/preferences.xml b/res/xml/preferences.xml index 21598d3421..666ee32098 100644 --- a/res/xml/preferences.xml +++ b/res/xml/preferences.xml @@ -42,7 +42,7 @@ android:icon="@drawable/icon_qr_code"/> Date: Mon, 21 Oct 2019 16:28:05 +1100 Subject: [PATCH 09/14] Limit allowed characters in display names --- src/org/thoughtcrime/securesms/CreateProfileActivity.java | 7 +++++++ src/org/thoughtcrime/securesms/loki/DisplayNameActivity.kt | 3 +++ 2 files changed, 10 insertions(+) diff --git a/src/org/thoughtcrime/securesms/CreateProfileActivity.java b/src/org/thoughtcrime/securesms/CreateProfileActivity.java index 975a9b443f..d30324ae2a 100644 --- a/src/org/thoughtcrime/securesms/CreateProfileActivity.java +++ b/src/org/thoughtcrime/securesms/CreateProfileActivity.java @@ -67,6 +67,8 @@ import java.io.IOException; import java.security.SecureRandom; import java.util.Set; import java.util.concurrent.ExecutionException; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import javax.inject.Inject; @@ -227,9 +229,14 @@ public class CreateProfileActivity extends BaseActionBarActivity implements Inje public void onTextChanged(CharSequence s, int start, int before, int count) {} @Override public void afterTextChanged(Editable s) { + Pattern pattern = Pattern.compile("[a-zA-Z0-9_]+"); + Matcher matcher = pattern.matcher(s.toString()); if (s.toString().isEmpty()) { name.getInput().setError("Invalid"); finishButton.setEnabled(false); + } else if (!matcher.matches()) { + name.getInput().setError("Invalid (a-z, A-Z, 0-9 and _ only)"); + finishButton.setEnabled(false); } else if (s.toString().getBytes().length > ProfileCipher.NAME_PADDED_LENGTH) { name.getInput().setError(getString(R.string.CreateProfileActivity_too_long)); finishButton.setEnabled(false); diff --git a/src/org/thoughtcrime/securesms/loki/DisplayNameActivity.kt b/src/org/thoughtcrime/securesms/loki/DisplayNameActivity.kt index bb7f97504e..c99f480a75 100644 --- a/src/org/thoughtcrime/securesms/loki/DisplayNameActivity.kt +++ b/src/org/thoughtcrime/securesms/loki/DisplayNameActivity.kt @@ -27,6 +27,9 @@ class DisplayNameActivity : BaseActionBarActivity() { if (name.isEmpty()) { return nameEditText.input.setError("Invalid") } + if (!name.matches(Regex("[a-zA-Z0-9_]+"))) { + return nameEditText.input.setError("Invalid (a-z, A-Z, 0-9 and _ only)") + } if (name.toByteArray().size > ProfileCipher.NAME_PADDED_LENGTH) { return nameEditText.input.setError("Too Long") } else { From 0421794b414d24fe871d2c8c8239141aa1de6b2c Mon Sep 17 00:00:00 2001 From: Mikunj Date: Tue, 22 Oct 2019 08:41:57 +1100 Subject: [PATCH 10/14] Limit upload retries. --- src/org/thoughtcrime/securesms/jobs/AttachmentUploadJob.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/org/thoughtcrime/securesms/jobs/AttachmentUploadJob.java b/src/org/thoughtcrime/securesms/jobs/AttachmentUploadJob.java index 0b31b7ecfe..9a091150ce 100644 --- a/src/org/thoughtcrime/securesms/jobs/AttachmentUploadJob.java +++ b/src/org/thoughtcrime/securesms/jobs/AttachmentUploadJob.java @@ -52,7 +52,7 @@ public class AttachmentUploadJob extends BaseJob implements InjectableType { this(new Job.Parameters.Builder() .addConstraint(NetworkConstraint.KEY) .setLifespan(TimeUnit.DAYS.toMillis(1)) - .setMaxAttempts(Parameters.UNLIMITED) + .setMaxAttempts(3) .build(), attachmentId, destination); } From 2d287076875b01310ff7a42013600a7b06917b55 Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Tue, 22 Oct 2019 09:39:42 +1100 Subject: [PATCH 11/14] Switch over to new link preview system --- .../securesms/loki/LokiPublicChatPoller.kt | 36 ++++++++++++++----- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/src/org/thoughtcrime/securesms/loki/LokiPublicChatPoller.kt b/src/org/thoughtcrime/securesms/loki/LokiPublicChatPoller.kt index 5cd1b4c95c..e448b2ef0a 100644 --- a/src/org/thoughtcrime/securesms/loki/LokiPublicChatPoller.kt +++ b/src/org/thoughtcrime/securesms/loki/LokiPublicChatPoller.kt @@ -103,22 +103,40 @@ class LokiPublicChatPoller(private val context: Context, private val group: Loki } else { null } - val attachments = message.attachments.map { attachment -> + val attachments = message.attachments.mapNotNull { attachment -> + if (attachment.kind != LokiPublicChatMessage.Attachment.Kind.Attachment) { return@mapNotNull null } SignalServiceAttachmentPointer( - attachment.serverID, - attachment.contentType, + attachment.serverID, + attachment.contentType, + ByteArray(0), + Optional.of(attachment.size), + Optional.absent(), + attachment.width, attachment.height, + Optional.absent(), + Optional.of(attachment.fileName), + false, + Optional.fromNullable(attachment.caption), + attachment.url) + } + val linkPreview = message.attachments.firstOrNull { it.kind == LokiPublicChatMessage.Attachment.Kind.LinkPreview } + val signalLinkPreviews = mutableListOf() + if (linkPreview != null) { + val attachment = SignalServiceAttachmentPointer( + linkPreview.serverID, + linkPreview.contentType, ByteArray(0), - Optional.of(attachment.size), + Optional.of(linkPreview.size), Optional.absent(), - attachment.width, attachment.height, + linkPreview.width, linkPreview.height, Optional.absent(), - Optional.of(attachment.fileName), + Optional.of(linkPreview.fileName), false, - Optional.fromNullable(attachment.caption), - attachment.url) + Optional.fromNullable(linkPreview.caption), + linkPreview.url) + signalLinkPreviews.add(SignalServiceDataMessage.Preview(linkPreview.linkPreviewURL!!, linkPreview.linkPreviewTitle!!, Optional.of(attachment))) } val body = if (message.body == message.timestamp.toString()) "" else message.body // Workaround for the fact that the back-end doesn't accept messages without a body - val serviceDataMessage = SignalServiceDataMessage(message.timestamp, serviceGroup, attachments, body, false, 0, false, null, false, quote, null, null, null) + val serviceDataMessage = SignalServiceDataMessage(message.timestamp, serviceGroup, attachments, body, false, 0, false, null, false, quote, null, signalLinkPreviews, null) val serviceContent = SignalServiceContent(serviceDataMessage, message.hexEncodedPublicKey, SignalServiceAddress.DEFAULT_DEVICE_ID, message.timestamp, false) val senderDisplayName = "${message.displayName} (...${message.hexEncodedPublicKey.takeLast(8)})" DatabaseFactory.getLokiUserDatabase(context).setServerDisplayName(group.id, message.hexEncodedPublicKey, senderDisplayName) From 17ee4bf7a8bd85e12446342422830cf83c391331 Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Tue, 22 Oct 2019 09:46:47 +1100 Subject: [PATCH 12/14] Ditch temporary link preview setup --- .../securesms/jobs/PushDecryptJob.java | 124 +++--------------- 1 file changed, 21 insertions(+), 103 deletions(-) diff --git a/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java b/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java index 3abcbcdaea..20fac5ef31 100644 --- a/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java +++ b/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java @@ -64,7 +64,6 @@ import org.thoughtcrime.securesms.jobmanager.Job; import org.thoughtcrime.securesms.jobmanager.JobManager; import org.thoughtcrime.securesms.linkpreview.Link; import org.thoughtcrime.securesms.linkpreview.LinkPreview; -import org.thoughtcrime.securesms.linkpreview.LinkPreviewRepository; import org.thoughtcrime.securesms.linkpreview.LinkPreviewUtil; import org.thoughtcrime.securesms.logging.Log; import org.thoughtcrime.securesms.loki.LokiAPIUtilities; @@ -760,38 +759,6 @@ public class PushDecryptJob extends BaseJob implements InjectableType { message.getExpiresInSeconds() * 1000L, false, content.isNeedsReceipt(), message.getBody(), message.getGroupInfo(), message.getAttachments(), quote, sharedContacts, linkPreviews, sticker); - if (linkPreviews.isPresent()) { - int linkPreviewCount = linkPreviews.get().size(); - if (linkPreviewCount != 0) { - LinkPreviewRepository lpr = new LinkPreviewRepository(context); - final int[] count = { 0 }; - for (LinkPreview linkPreview : linkPreviews.get()) { - lpr.getLinkPreview(context, linkPreview.getUrl(), lp -> Util.runOnMain(() -> { - int c = count[0]; - c = c + 1; - count[0] = c; - if (lp.isPresent() && lp.get().getThumbnail().isPresent()) { - Attachment thumbnail = lp.get().getThumbnail().get(); - linkPreview.thumbnail = Optional.of(thumbnail); - } - if (c == linkPreviewCount) { - try { - handleMediaMessage(content, mediaMessage, smsMessageId, messageServerIDOrNull); - } catch (Exception e) { - // TODO: Handle - } - } - })); - } - } else { - handleMediaMessage(content, mediaMessage, smsMessageId, messageServerIDOrNull); - } - } else { - handleMediaMessage(content, mediaMessage, smsMessageId, messageServerIDOrNull); - } - } - - private void handleMediaMessage(@NonNull SignalServiceContent content, @NonNull IncomingMediaMessage mediaMessage, @NonNull Optional smsMessageID, @Nullable Optional messageServerIDOrNull) throws StorageFailedException { MmsDatabase database = DatabaseFactory.getMmsDatabase(context); database.beginTransaction(); @@ -816,8 +783,8 @@ public class PushDecryptJob extends BaseJob implements InjectableType { ApplicationContext.getInstance(context).getJobManager().add(new AttachmentDownloadJob(insertResult.get().getMessageId(), attachment.getAttachmentId(), false)); } - if (smsMessageID.isPresent()) { - DatabaseFactory.getSmsDatabase(context).deleteMessage(smsMessageID.get()); + if (smsMessageId.isPresent()) { + DatabaseFactory.getSmsDatabase(context).deleteMessage(smsMessageId.get()); } database.setTransactionSuccessful(); @@ -967,79 +934,30 @@ public class PushDecryptJob extends BaseJob implements InjectableType { IncomingEncryptedMessage textMessage = new IncomingEncryptedMessage(_textMessage, body); - List urls = LinkPreviewUtil.findWhitelistedUrls(body); - int urlCount = urls.size(); - if (urlCount != 0) { - IncomingMediaMessage mediaMessage = new IncomingMediaMessage(Address.fromExternal(context, content.getSender()), message.getTimestamp(), -1, - message.getExpiresInSeconds() * 1000L, false, content.isNeedsReceipt(), message.getBody(), message.getGroupInfo(), message.getAttachments(), - Optional.absent(), Optional.absent(), Optional.of(new ArrayList<>()), Optional.absent()); - LinkPreviewRepository lpr = new LinkPreviewRepository(context); - final int[] count = { 0 }; - for (Link url : urls) { - lpr.getLinkPreview(context, url.getUrl(), lp -> Util.runOnMain(() -> { - int c = count[0]; - c = c + 1; - count[0] = c; - if (lp.isPresent()) { mediaMessage.getLinkPreviews().add(lp.get()); } - if (c == urlCount) { - try { - handleMediaMessage(content, mediaMessage, smsMessageId, messageServerIDOrNull); - } catch (Exception e) { - // TODO: Handle - } - } - })); - } - } else if (LinkPreviewUtil.isWhitelistedMediaUrl(body)) { - new LinkPreviewRepository(context).fetchGIF(context, body, attachmentOrNull -> Util.runOnMain(() -> { - if (attachmentOrNull.isPresent()) { - Attachment attachment = attachmentOrNull.get(); - try { - IncomingMediaMessage mediaMessage = new IncomingMediaMessage(Address.fromExternal(context, content.getSender()), message.getTimestamp(), -1, - message.getExpiresInSeconds() * 1000L, false, content.isNeedsReceipt(), message.getBody(), message.getGroupInfo(), Optional.of(new ArrayList<>()), - Optional.absent(), Optional.absent(), Optional.absent(), Optional.absent()); - mediaMessage.getAttachments().add(attachment); - handleMediaMessage(content, mediaMessage, smsMessageId, messageServerIDOrNull); - } catch (Exception e) { - // TODO: Handle - } - } else { - handleTextMessage(message, textMessage, smsMessageId, messageServerIDOrNull); - } - })); - } else { - handleTextMessage(message, textMessage, smsMessageId, messageServerIDOrNull); - } - } - } - - private void handleTextMessage(@NonNull SignalServiceDataMessage message, @NonNull IncomingTextMessage textMessage, @NonNull Optional smsMessageId, @NonNull Optional messageServerIDOrNull) { - SmsDatabase database = DatabaseFactory.getSmsDatabase(context); - - // Ignore the message if the body is empty - if (textMessage.getMessageBody().length() == 0) { return; } + // Ignore the message if the body is empty + if (textMessage.getMessageBody().length() == 0) { return; } - // Insert the message into the database - Optional insertResult = database.insertMessageInbox(textMessage); - - Long threadId; - if (insertResult.isPresent()) threadId = insertResult.get().getThreadId(); - else threadId = null; + // Insert the message into the database + Optional insertResult = database.insertMessageInbox(textMessage); + + if (insertResult.isPresent()) threadId = insertResult.get().getThreadId(); + else threadId = null; - if (smsMessageId.isPresent()) database.deleteMessage(smsMessageId.get()); + if (smsMessageId.isPresent()) database.deleteMessage(smsMessageId.get()); - // Loki - Cache the user hex encoded public key (for mentions) - if (threadId != null) { - LokiAPIUtilities.INSTANCE.populateUserHexEncodedPublicKeyCacheIfNeeded(threadId, context); - LokiAPI.Companion.cache(textMessage.getSender().serialize(), threadId); - } + // Loki - Cache the user hex encoded public key (for mentions) + if (threadId != null) { + LokiAPIUtilities.INSTANCE.populateUserHexEncodedPublicKeyCacheIfNeeded(threadId, context); + LokiAPI.Companion.cache(textMessage.getSender().serialize(), threadId); + } - // Loki - Store message server ID - updateGroupChatMessageServerID(messageServerIDOrNull, insertResult); + // Loki - Store message server ID + updateGroupChatMessageServerID(messageServerIDOrNull, insertResult); - boolean isGroupMessage = message.getGroupInfo().isPresent(); - if (threadId != null && !isGroupMessage) { - MessageNotifier.updateNotification(context, threadId); + boolean isGroupMessage = message.getGroupInfo().isPresent(); + if (threadId != null && !isGroupMessage) { + MessageNotifier.updateNotification(context, threadId); + } } } From 4aa1eed9794a2121ecbf16f3e654ec5e03ba1c93 Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Tue, 22 Oct 2019 10:09:46 +1100 Subject: [PATCH 13/14] Debug --- src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java | 2 +- src/org/thoughtcrime/securesms/jobs/PushMediaSendJob.java | 1 - src/org/thoughtcrime/securesms/loki/LokiPublicChatPoller.kt | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java b/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java index 20fac5ef31..625efd9455 100644 --- a/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java +++ b/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java @@ -939,7 +939,7 @@ public class PushDecryptJob extends BaseJob implements InjectableType { // Insert the message into the database Optional insertResult = database.insertMessageInbox(textMessage); - + if (insertResult.isPresent()) threadId = insertResult.get().getThreadId(); else threadId = null; diff --git a/src/org/thoughtcrime/securesms/jobs/PushMediaSendJob.java b/src/org/thoughtcrime/securesms/jobs/PushMediaSendJob.java index bcfe4b9de0..263dedc322 100644 --- a/src/org/thoughtcrime/securesms/jobs/PushMediaSendJob.java +++ b/src/org/thoughtcrime/securesms/jobs/PushMediaSendJob.java @@ -104,7 +104,6 @@ public class PushMediaSendJob extends PushSendJob implements InjectableType { OutgoingMediaMessage message = database.getOutgoingMessage(messageId); List attachments = new LinkedList<>(); - // Loki - For now all attachments are re-fetched by the receiver attachments.addAll(message.getAttachments()); attachments.addAll(Stream.of(message.getLinkPreviews()).filter(p -> p.getThumbnail().isPresent()).map(p -> p.getThumbnail().get()).toList()); attachments.addAll(Stream.of(message.getSharedContacts()).filter(c -> c.getAvatar() != null).map(c -> c.getAvatar().getAttachment()).withoutNulls().toList()); diff --git a/src/org/thoughtcrime/securesms/loki/LokiPublicChatPoller.kt b/src/org/thoughtcrime/securesms/loki/LokiPublicChatPoller.kt index e448b2ef0a..3e6685e429 100644 --- a/src/org/thoughtcrime/securesms/loki/LokiPublicChatPoller.kt +++ b/src/org/thoughtcrime/securesms/loki/LokiPublicChatPoller.kt @@ -140,7 +140,7 @@ class LokiPublicChatPoller(private val context: Context, private val group: Loki val serviceContent = SignalServiceContent(serviceDataMessage, message.hexEncodedPublicKey, SignalServiceAddress.DEFAULT_DEVICE_ID, message.timestamp, false) val senderDisplayName = "${message.displayName} (...${message.hexEncodedPublicKey.takeLast(8)})" DatabaseFactory.getLokiUserDatabase(context).setServerDisplayName(group.id, message.hexEncodedPublicKey, senderDisplayName) - if (quote != null || attachments.count() > 0) { + if (quote != null || attachments.count() > 0 || linkPreview != null) { PushDecryptJob(context).handleMediaMessage(serviceContent, serviceDataMessage, Optional.absent(), Optional.of(message.serverID)) } else { PushDecryptJob(context).handleTextMessage(serviceContent, serviceDataMessage, Optional.absent(), Optional.of(message.serverID)) From a08f4caccbfd5750c4978bfa605d3503682180f7 Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Tue, 22 Oct 2019 11:25:00 +1100 Subject: [PATCH 14/14] Fix camera button position --- res/layout/conversation_activity.xml | 1 - res/layout/conversation_input_panel.xml | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/res/layout/conversation_activity.xml b/res/layout/conversation_activity.xml index 9c791f205f..6d2e36cbb8 100644 --- a/res/layout/conversation_activity.xml +++ b/res/layout/conversation_activity.xml @@ -125,7 +125,6 @@ android:text="160/160 (1)" android:visibility="gone" /> -