From 7d1b4c363f16556999ae12809239e7ed2443e756 Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Wed, 11 Sep 2019 10:08:38 +1000 Subject: [PATCH 1/4] Add beta terms label --- res/layout/registration_welcome_activity.xml | 22 +++++++++++++++++--- res/values/strings.xml | 1 + 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/res/layout/registration_welcome_activity.xml b/res/layout/registration_welcome_activity.xml index 69cb628f33..d08003387a 100644 --- a/res/layout/registration_welcome_activity.xml +++ b/res/layout/registration_welcome_activity.xml @@ -1,7 +1,7 @@ - @@ -26,7 +26,7 @@ app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/textView" app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintBottom_toTopOf="@id/welcome_terms_button" + app:layout_constraintBottom_toTopOf="@id/beta_terms_label" android:orientation="vertical" android:gravity="center"> @@ -37,6 +37,21 @@ + + diff --git a/res/values/strings.xml b/res/values/strings.xml index 6488c933b5..10f66eeca1 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -1547,6 +1547,7 @@ Loki Messenger Some features of Loki Messenger (such as automatic message backup) require storage access to work. + "Loki Messenger is currently in beta. For development purposes the beta version collects basic usage statistics and crash logs. In addition, the beta version doesn't provide full privacy and shouldn\'t be used to transmit sensitive information." Privacy Policy Create Your Loki Messenger Account From 88a5b7a87f4ea93291f79fe8e29bcac320aa9c4a Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Wed, 11 Sep 2019 15:52:32 +1000 Subject: [PATCH 2/4] Implement quotes in group chats --- .../conversation/ConversationFragment.java | 4 +-- .../securesms/jobs/PushDecryptJob.java | 25 +++++++++------ .../securesms/loki/LokiGroupChatPoller.kt | 31 +++++++++++++------ 3 files changed, 39 insertions(+), 21 deletions(-) diff --git a/src/org/thoughtcrime/securesms/conversation/ConversationFragment.java b/src/org/thoughtcrime/securesms/conversation/ConversationFragment.java index 585dc5b01d..1496074fbd 100644 --- a/src/org/thoughtcrime/securesms/conversation/ConversationFragment.java +++ b/src/org/thoughtcrime/securesms/conversation/ConversationFragment.java @@ -406,11 +406,11 @@ public class ConversationFragment extends Fragment menu.findItem(R.id.menu_context_copy).setVisible(!actionMessage && hasText); boolean isGroupChat = recipient.isGroupRecipient(); + boolean isLokiPublicChat = recipient.getName() != null && recipient.getName().equals("Loki Public Chat"); if (isGroupChat) { - menu.findItem(R.id.menu_context_reply).setVisible(false); + menu.findItem(R.id.menu_context_reply).setVisible(isLokiPublicChat); LokiAPIDatabase lokiAPIDatabase = DatabaseFactory.getLokiAPIDatabase(getContext()); - boolean isLokiPublicChat = recipient.getName().equals("Loki Public Chat"); int selectedMessageCount = messageRecords.size(); boolean isSentByUser = ((MessageRecord)messageRecords.toArray()[0]).isOutgoing(); boolean userCanModerate = lokiAPIDatabase.isModerator(LokiGroupChatAPI.getPublicChatServerID(), LokiGroupChatAPI.getPublicChatServer()); diff --git a/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java b/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java index e23f87b8a2..f741cc2860 100644 --- a/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java +++ b/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java @@ -305,7 +305,7 @@ public class PushDecryptJob extends BaseJob implements InjectableType { if (message.isEndSession()) handleEndSessionMessage(content, smsMessageId); else if (message.isGroupUpdate()) handleGroupMessage(content, message, smsMessageId); else if (message.isExpirationUpdate()) handleExpirationUpdate(content, message, smsMessageId); - else if (isMediaMessage) handleMediaMessage(content, message, smsMessageId); + else if (isMediaMessage) handleMediaMessage(content, message, smsMessageId, Optional.absent()); else if (message.getBody().isPresent()) handleTextMessage(content, message, smsMessageId, Optional.absent()); if (message.getGroupInfo().isPresent() && groupDatabase.isUnknownGroup(GroupUtil.getEncodedId(message.getGroupInfo().get().getGroupId(), false))) { @@ -733,9 +733,10 @@ public class PushDecryptJob extends BaseJob implements InjectableType { MessageNotifier.updateNotification(context); } - private void handleMediaMessage(@NonNull SignalServiceContent content, - @NonNull SignalServiceDataMessage message, - @NonNull Optional smsMessageId) + public void handleMediaMessage(@NonNull SignalServiceContent content, + @NonNull SignalServiceDataMessage message, + @NonNull Optional smsMessageId, + @Nullable Optional messageServerIDOrNull) throws StorageFailedException { notifyTypingStoppedFromIncomingMessage(getMessageDestination(content, message), content.getSender(), content.getSenderDevice()); @@ -764,7 +765,7 @@ public class PushDecryptJob extends BaseJob implements InjectableType { } if (c == linkPreviewCount) { try { - handleMediaMessage(content, mediaMessage, smsMessageId); + handleMediaMessage(content, mediaMessage, smsMessageId, messageServerIDOrNull); } catch (Exception e) { // TODO: Handle } @@ -772,14 +773,14 @@ public class PushDecryptJob extends BaseJob implements InjectableType { })); } } else { - handleMediaMessage(content, mediaMessage, smsMessageId); + handleMediaMessage(content, mediaMessage, smsMessageId, messageServerIDOrNull); } } else { - handleMediaMessage(content, mediaMessage, smsMessageId); + handleMediaMessage(content, mediaMessage, smsMessageId, messageServerIDOrNull); } } - private void handleMediaMessage(@NonNull SignalServiceContent content, @NonNull IncomingMediaMessage mediaMessage, @NonNull Optional smsMessageID) throws StorageFailedException { + private void handleMediaMessage(@NonNull SignalServiceContent content, @NonNull IncomingMediaMessage mediaMessage, @NonNull Optional smsMessageID, @Nullable Optional messageServerIDOrNull) throws StorageFailedException { MmsDatabase database = DatabaseFactory.getMmsDatabase(context); database.beginTransaction(); @@ -811,6 +812,12 @@ public class PushDecryptJob extends BaseJob implements InjectableType { database.endTransaction(); } + if (insertResult.isPresent() && messageServerIDOrNull.isPresent()) { + long messageID = insertResult.get().getMessageId(); + long messageServerID = messageServerIDOrNull.get(); + DatabaseFactory.getLokiMessageDatabase(context).setServerID(messageID, messageServerID); + } + if (insertResult.isPresent()) { MessageNotifier.updateNotification(context, insertResult.get().getThreadId()); } @@ -963,7 +970,7 @@ public class PushDecryptJob extends BaseJob implements InjectableType { if (lp.isPresent()) { mediaMessage.getLinkPreviews().add(lp.get()); } if (c == urlCount) { try { - handleMediaMessage(content, mediaMessage, smsMessageId); + handleMediaMessage(content, mediaMessage, smsMessageId, messageServerIDOrNull); } catch (Exception e) { // TODO: Handle } diff --git a/src/org/thoughtcrime/securesms/loki/LokiGroupChatPoller.kt b/src/org/thoughtcrime/securesms/loki/LokiGroupChatPoller.kt index 4b6afca3fc..b1bb313f94 100644 --- a/src/org/thoughtcrime/securesms/loki/LokiGroupChatPoller.kt +++ b/src/org/thoughtcrime/securesms/loki/LokiGroupChatPoller.kt @@ -3,19 +3,15 @@ package org.thoughtcrime.securesms.loki import android.content.Context import android.os.Handler import android.util.Log -import org.thoughtcrime.securesms.attachments.Attachment -import org.thoughtcrime.securesms.contactshare.Contact import org.thoughtcrime.securesms.crypto.IdentityKeyUtil import org.thoughtcrime.securesms.database.Address import org.thoughtcrime.securesms.database.DatabaseFactory import org.thoughtcrime.securesms.database.ThreadDatabase -import org.thoughtcrime.securesms.database.documents.IdentityKeyMismatch -import org.thoughtcrime.securesms.database.documents.NetworkFailure import org.thoughtcrime.securesms.jobs.PushDecryptJob -import org.thoughtcrime.securesms.linkpreview.LinkPreview import org.thoughtcrime.securesms.linkpreview.LinkPreviewRepository import org.thoughtcrime.securesms.linkpreview.LinkPreviewUtil import org.thoughtcrime.securesms.mms.OutgoingMediaMessage +import org.thoughtcrime.securesms.mms.QuoteModel import org.thoughtcrime.securesms.recipients.Recipient import org.thoughtcrime.securesms.util.GroupUtil import org.thoughtcrime.securesms.util.TextSecurePreferences @@ -28,7 +24,6 @@ import org.whispersystems.signalservice.api.push.SignalServiceAddress import org.whispersystems.signalservice.loki.api.LokiGroupChat import org.whispersystems.signalservice.loki.api.LokiGroupChatAPI import org.whispersystems.signalservice.loki.api.LokiGroupMessage -import java.util.* class LokiGroupChatPoller(private val context: Context, private val group: LokiGroupChat) { private val handler = Handler() @@ -102,11 +97,21 @@ class LokiGroupChatPoller(private val context: Context, private val group: LokiG fun processIncomingMessage(message: LokiGroupMessage) { val id = group.id.toByteArray() val x1 = SignalServiceGroup(SignalServiceGroup.Type.UPDATE, id, null, null, null) - val x2 = SignalServiceDataMessage(message.timestamp, x1, null, message.body) + val quote: SignalServiceDataMessage.Quote? + if (message.quote != null) { + quote = SignalServiceDataMessage.Quote(message.quote!!.quotedMessageTimestamp, SignalServiceAddress(message.quote!!.quoteeHexEncodedPublicKey), message.quote!!.quotedMessageBody, listOf()) + } else { + quote = null + } + 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 senderDisplayName = "${message.displayName} (...${message.hexEncodedPublicKey.takeLast(8)})" DatabaseFactory.getLokiUserDatabase(context).setServerDisplayName(group.id, message.hexEncodedPublicKey, senderDisplayName) - PushDecryptJob(context).handleTextMessage(x3, x2, Optional.absent(), Optional.of(message.serverID)) + if (quote != null) { + PushDecryptJob(context).handleMediaMessage(x3, x2, Optional.absent(), Optional.of(message.serverID)) + } else { + PushDecryptJob(context).handleTextMessage(x3, x2, Optional.absent(), Optional.of(message.serverID)) + } } fun processOutgoingMessage(message: LokiGroupMessage) { val messageServerID = message.serverID ?: return @@ -116,8 +121,14 @@ class LokiGroupChatPoller(private val context: Context, private val group: LokiG val id = group.id.toByteArray() val mmsDatabase = DatabaseFactory.getMmsDatabase(context) val recipient = Recipient.from(context, Address.fromSerialized(GroupUtil.getEncodedId(id, false)), false) - val signalMessage = OutgoingMediaMessage(recipient, message.body, ArrayList(), message.timestamp, 0, 0, ThreadDatabase.DistributionTypes.DEFAULT, - null, ArrayList(), ArrayList(), ArrayList(), ArrayList()) + val quote: QuoteModel? + if (message.quote != null) { + quote = QuoteModel(message.quote!!.quotedMessageTimestamp, Address.fromSerialized(message.quote!!.quoteeHexEncodedPublicKey), message.quote!!.quotedMessageBody, false, listOf()) + } else { + quote = null + } + val signalMessage = OutgoingMediaMessage(recipient, message.body, listOf(), message.timestamp, 0, 0, + ThreadDatabase.DistributionTypes.DEFAULT, quote, listOf(), listOf(), listOf(), listOf()) val threadID = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipient) fun finalize() { val messageID = mmsDatabase.insertMessageOutbox(signalMessage, threadID, false, null) From f3c4098f147c82cc2ecfdc3c294a539f437410b4 Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Wed, 11 Sep 2019 16:28:07 +1000 Subject: [PATCH 3/4] Disallow quoting multiple messages simultaneously --- .../securesms/conversation/ConversationFragment.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/org/thoughtcrime/securesms/conversation/ConversationFragment.java b/src/org/thoughtcrime/securesms/conversation/ConversationFragment.java index 1496074fbd..074ac80b89 100644 --- a/src/org/thoughtcrime/securesms/conversation/ConversationFragment.java +++ b/src/org/thoughtcrime/securesms/conversation/ConversationFragment.java @@ -406,12 +406,12 @@ public class ConversationFragment extends Fragment menu.findItem(R.id.menu_context_copy).setVisible(!actionMessage && hasText); boolean isGroupChat = recipient.isGroupRecipient(); - boolean isLokiPublicChat = recipient.getName() != null && recipient.getName().equals("Loki Public Chat"); if (isGroupChat) { - menu.findItem(R.id.menu_context_reply).setVisible(isLokiPublicChat); - LokiAPIDatabase lokiAPIDatabase = DatabaseFactory.getLokiAPIDatabase(getContext()); + boolean isLokiPublicChat = recipient.getName() != null && recipient.getName().equals("Loki Public Chat"); int selectedMessageCount = messageRecords.size(); + menu.findItem(R.id.menu_context_reply).setVisible(isLokiPublicChat && selectedMessageCount == 1); + LokiAPIDatabase lokiAPIDatabase = DatabaseFactory.getLokiAPIDatabase(getContext()); boolean isSentByUser = ((MessageRecord)messageRecords.toArray()[0]).isOutgoing(); boolean userCanModerate = lokiAPIDatabase.isModerator(LokiGroupChatAPI.getPublicChatServerID(), LokiGroupChatAPI.getPublicChatServer()); boolean isDeleteOptionVisible = isLokiPublicChat && selectedMessageCount == 1 && (isSentByUser || userCanModerate); From f3dc4f51e1697857605c5e54581dbc93912b2028 Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Wed, 11 Sep 2019 16:36:02 +1000 Subject: [PATCH 4/4] Fix group chat quote display name --- .../thoughtcrime/securesms/components/QuoteView.java | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/org/thoughtcrime/securesms/components/QuoteView.java b/src/org/thoughtcrime/securesms/components/QuoteView.java index 63f66cfa7b..ef9dccff24 100644 --- a/src/org/thoughtcrime/securesms/components/QuoteView.java +++ b/src/org/thoughtcrime/securesms/components/QuoteView.java @@ -20,8 +20,8 @@ import android.widget.TextView; import com.annimon.stream.Stream; import com.bumptech.glide.load.engine.DiskCacheStrategy; -import network.loki.messenger.R; import org.thoughtcrime.securesms.attachments.Attachment; +import org.thoughtcrime.securesms.database.DatabaseFactory; import org.thoughtcrime.securesms.mms.DecryptableStreamUriLoader.DecryptableUri; import org.thoughtcrime.securesms.mms.GlideRequests; import org.thoughtcrime.securesms.mms.Slide; @@ -30,9 +30,12 @@ import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.recipients.RecipientModifiedListener; import org.thoughtcrime.securesms.util.ThemeUtil; import org.thoughtcrime.securesms.util.Util; +import org.whispersystems.signalservice.loki.api.LokiGroupChatAPI; import java.util.List; +import network.loki.messenger.R; + public class QuoteView extends FrameLayout implements RecipientModifiedListener { private static final String TAG = QuoteView.class.getSimpleName(); @@ -186,8 +189,11 @@ public class QuoteView extends FrameLayout implements RecipientModifiedListener boolean outgoing = messageType != MESSAGE_TYPE_INCOMING; boolean isOwnNumber = Util.isOwnNumber(getContext(), author.getAddress()); - authorView.setText(isOwnNumber ? getContext().getString(R.string.QuoteView_you) - : author.toShortString()); + String quoteeDisplayName = author.toShortString(); + if (quoteeDisplayName.equals(author.getAddress().toString())) { + quoteeDisplayName = DatabaseFactory.getLokiUserDatabase(getContext()).getServerDisplayName(LokiGroupChatAPI.getPublicChatServer() + "." + LokiGroupChatAPI.getPublicChatServerID(), author.getAddress().toString()); + } + authorView.setText(isOwnNumber ? getContext().getString(R.string.QuoteView_you) : quoteeDisplayName); // We use the raw color resource because Android 4.x was struggling with tints here quoteBarView.setImageResource(author.getColor().toQuoteBarColorResource(getContext(), outgoing));