Merge branch 'dev' of github.com:loki-project/loki-messenger-android into bug-fixes

# Conflicts:
#	src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java
This commit is contained in:
Niels Andriesse 2019-09-12 09:46:12 +10:00
commit 3b242e7435
6 changed files with 63 additions and 32 deletions

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" <android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:background="@color/loki_darkest_gray" android:background="@color/loki_darkest_gray"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent">
@ -26,7 +26,7 @@
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/textView" app:layout_constraintTop_toBottomOf="@id/textView"
app:layout_constraintEnd_toEndOf="parent" 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:orientation="vertical"
android:gravity="center"> android:gravity="center">
@ -37,6 +37,21 @@
</LinearLayout> </LinearLayout>
<TextView
android:id="@+id/beta_terms_label"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="32dp"
android:layout_marginEnd="32dp"
android:layout_marginBottom="24dp"
style="@style/Signal.Text.Body"
android:text="@string/activity_landing_beta_terms"
android:textColor="@color/white"
android:textAlignment="center"
app:layout_constraintBottom_toTopOf="@+id/welcome_terms_button"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<TextView <TextView
android:id="@+id/welcome_terms_button" android:id="@+id/welcome_terms_button"
android:layout_width="wrap_content" android:layout_width="wrap_content"
@ -45,6 +60,7 @@
style="@style/Signal.Text.Body" style="@style/Signal.Text.Body"
android:text="@string/activity_landing_privacy_policy_button_title" android:text="@string/activity_landing_privacy_policy_button_title"
android:textColor="@color/signal_primary" android:textColor="@color/signal_primary"
android:textAlignment="center"
app:layout_constraintBottom_toTopOf="@+id/welcome_continue_button" app:layout_constraintBottom_toTopOf="@+id/welcome_continue_button"
app:layout_constraintEnd_toEndOf="@+id/welcome_continue_button" app:layout_constraintEnd_toEndOf="@+id/welcome_continue_button"
app:layout_constraintStart_toStartOf="@+id/welcome_continue_button" /> app:layout_constraintStart_toStartOf="@+id/welcome_continue_button" />

View File

@ -1547,6 +1547,7 @@
<!-- Landing activity --> <!-- Landing activity -->
<string name="activity_landing_title">Loki Messenger</string> <string name="activity_landing_title">Loki Messenger</string>
<string name="activity_landing_permission_dialog_message">Some features of Loki Messenger (such as automatic message backup) require storage access to work.</string> <string name="activity_landing_permission_dialog_message">Some features of Loki Messenger (such as automatic message backup) require storage access to work.</string>
<string name="activity_landing_beta_terms">"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."</string>
<string name="activity_landing_privacy_policy_button_title">Privacy Policy</string> <string name="activity_landing_privacy_policy_button_title">Privacy Policy</string>
<!-- Account details activity --> <!-- Account details activity -->
<string name="activity_account_details_title">Create Your Loki Messenger Account</string> <string name="activity_account_details_title">Create Your Loki Messenger Account</string>

View File

@ -20,8 +20,8 @@ import android.widget.TextView;
import com.annimon.stream.Stream; import com.annimon.stream.Stream;
import com.bumptech.glide.load.engine.DiskCacheStrategy; import com.bumptech.glide.load.engine.DiskCacheStrategy;
import network.loki.messenger.R;
import org.thoughtcrime.securesms.attachments.Attachment; import org.thoughtcrime.securesms.attachments.Attachment;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.mms.DecryptableStreamUriLoader.DecryptableUri; import org.thoughtcrime.securesms.mms.DecryptableStreamUriLoader.DecryptableUri;
import org.thoughtcrime.securesms.mms.GlideRequests; import org.thoughtcrime.securesms.mms.GlideRequests;
import org.thoughtcrime.securesms.mms.Slide; 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.recipients.RecipientModifiedListener;
import org.thoughtcrime.securesms.util.ThemeUtil; import org.thoughtcrime.securesms.util.ThemeUtil;
import org.thoughtcrime.securesms.util.Util; import org.thoughtcrime.securesms.util.Util;
import org.whispersystems.signalservice.loki.api.LokiGroupChatAPI;
import java.util.List; import java.util.List;
import network.loki.messenger.R;
public class QuoteView extends FrameLayout implements RecipientModifiedListener { public class QuoteView extends FrameLayout implements RecipientModifiedListener {
private static final String TAG = QuoteView.class.getSimpleName(); 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 outgoing = messageType != MESSAGE_TYPE_INCOMING;
boolean isOwnNumber = Util.isOwnNumber(getContext(), author.getAddress()); boolean isOwnNumber = Util.isOwnNumber(getContext(), author.getAddress());
authorView.setText(isOwnNumber ? getContext().getString(R.string.QuoteView_you) String quoteeDisplayName = author.toShortString();
: 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 // We use the raw color resource because Android 4.x was struggling with tints here
quoteBarView.setImageResource(author.getColor().toQuoteBarColorResource(getContext(), outgoing)); quoteBarView.setImageResource(author.getColor().toQuoteBarColorResource(getContext(), outgoing));

View File

@ -408,10 +408,10 @@ public class ConversationFragment extends Fragment
boolean isGroupChat = recipient.isGroupRecipient(); boolean isGroupChat = recipient.isGroupRecipient();
if (isGroupChat) { if (isGroupChat) {
menu.findItem(R.id.menu_context_reply).setVisible(false); boolean isLokiPublicChat = recipient.getName() != null && recipient.getName().equals("Loki Public Chat");
LokiAPIDatabase lokiAPIDatabase = DatabaseFactory.getLokiAPIDatabase(getContext());
boolean isLokiPublicChat = recipient.getName().equals("Loki Public Chat");
int selectedMessageCount = messageRecords.size(); 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 isSentByUser = ((MessageRecord)messageRecords.toArray()[0]).isOutgoing();
boolean userCanModerate = lokiAPIDatabase.isModerator(LokiGroupChatAPI.getPublicChatServerID(), LokiGroupChatAPI.getPublicChatServer()); boolean userCanModerate = lokiAPIDatabase.isModerator(LokiGroupChatAPI.getPublicChatServerID(), LokiGroupChatAPI.getPublicChatServer());
boolean isDeleteOptionVisible = isLokiPublicChat && selectedMessageCount == 1 && (isSentByUser || userCanModerate); boolean isDeleteOptionVisible = isLokiPublicChat && selectedMessageCount == 1 && (isSentByUser || userCanModerate);

View File

@ -305,7 +305,7 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
if (message.isEndSession()) handleEndSessionMessage(content, smsMessageId); if (message.isEndSession()) handleEndSessionMessage(content, smsMessageId);
else if (message.isGroupUpdate()) handleGroupMessage(content, message, smsMessageId); else if (message.isGroupUpdate()) handleGroupMessage(content, message, smsMessageId);
else if (message.isExpirationUpdate()) handleExpirationUpdate(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()); else if (message.getBody().isPresent()) handleTextMessage(content, message, smsMessageId, Optional.absent());
if (message.getGroupInfo().isPresent() && groupDatabase.isUnknownGroup(GroupUtil.getEncodedId(message.getGroupInfo().get().getGroupId(), false))) { 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); MessageNotifier.updateNotification(context);
} }
private void handleMediaMessage(@NonNull SignalServiceContent content, public void handleMediaMessage(@NonNull SignalServiceContent content,
@NonNull SignalServiceDataMessage message, @NonNull SignalServiceDataMessage message,
@NonNull Optional<Long> smsMessageId) @NonNull Optional<Long> smsMessageId,
@NonNull Optional<Long> messageServerIDOrNull)
throws StorageFailedException throws StorageFailedException
{ {
notifyTypingStoppedFromIncomingMessage(getMessageDestination(content, message), content.getSender(), content.getSenderDevice()); notifyTypingStoppedFromIncomingMessage(getMessageDestination(content, message), content.getSender(), content.getSenderDevice());
@ -764,7 +765,7 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
} }
if (c == linkPreviewCount) { if (c == linkPreviewCount) {
try { try {
handleMediaMessage(content, mediaMessage, smsMessageId); handleMediaMessage(content, mediaMessage, smsMessageId, messageServerIDOrNull);
} catch (Exception e) { } catch (Exception e) {
// TODO: Handle // TODO: Handle
} }
@ -772,17 +773,13 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
})); }));
} }
} else { } else {
handleMediaMessage(content, mediaMessage, smsMessageId); handleMediaMessage(content, mediaMessage, smsMessageId, messageServerIDOrNull);
} }
} else { } else {
handleMediaMessage(content, mediaMessage, smsMessageId); handleMediaMessage(content, mediaMessage, smsMessageId, messageServerIDOrNull);
} }
} }
private void handleMediaMessage(@NonNull SignalServiceContent content, @NonNull IncomingMediaMessage mediaMessage, @NonNull Optional<Long> smsMessageID) throws StorageFailedException {
handleMediaMessage(content, mediaMessage, smsMessageID, null);
}
private void handleMediaMessage(@NonNull SignalServiceContent content, @NonNull IncomingMediaMessage mediaMessage, @NonNull Optional<Long> smsMessageID, @Nullable Optional<Long> messageServerIDOrNull) throws StorageFailedException { private void handleMediaMessage(@NonNull SignalServiceContent content, @NonNull IncomingMediaMessage mediaMessage, @NonNull Optional<Long> smsMessageID, @Nullable Optional<Long> messageServerIDOrNull) throws StorageFailedException {
MmsDatabase database = DatabaseFactory.getMmsDatabase(context); MmsDatabase database = DatabaseFactory.getMmsDatabase(context);
database.beginTransaction(); database.beginTransaction();
@ -927,7 +924,7 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
public void handleTextMessage(@NonNull SignalServiceContent content, public void handleTextMessage(@NonNull SignalServiceContent content,
@NonNull SignalServiceDataMessage message, @NonNull SignalServiceDataMessage message,
@NonNull Optional<Long> smsMessageId, @NonNull Optional<Long> smsMessageId,
@Nullable Optional<Long> messageServerIDOrNull) @NonNull Optional<Long> messageServerIDOrNull)
throws StorageFailedException throws StorageFailedException
{ {
SmsDatabase database = DatabaseFactory.getSmsDatabase(context); SmsDatabase database = DatabaseFactory.getSmsDatabase(context);
@ -996,7 +993,7 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
} }
} }
private void updatePublicChatMessageWithServerID(@Nullable Optional<Long> messageServerIDOrNull, Optional<InsertResult> databaseInsert) { private void updatePublicChatMessageWithServerID(Optional<Long> messageServerIDOrNull, Optional<InsertResult> databaseInsert) {
if (messageServerIDOrNull == null) { return; } if (messageServerIDOrNull == null) { return; }
if (databaseInsert.isPresent() && messageServerIDOrNull.isPresent()) { if (databaseInsert.isPresent() && messageServerIDOrNull.isPresent()) {
long messageID = databaseInsert.get().getMessageId(); long messageID = databaseInsert.get().getMessageId();

View File

@ -3,19 +3,15 @@ package org.thoughtcrime.securesms.loki
import android.content.Context import android.content.Context
import android.os.Handler import android.os.Handler
import android.util.Log 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.crypto.IdentityKeyUtil
import org.thoughtcrime.securesms.database.Address import org.thoughtcrime.securesms.database.Address
import org.thoughtcrime.securesms.database.DatabaseFactory import org.thoughtcrime.securesms.database.DatabaseFactory
import org.thoughtcrime.securesms.database.ThreadDatabase 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.jobs.PushDecryptJob
import org.thoughtcrime.securesms.linkpreview.LinkPreview
import org.thoughtcrime.securesms.linkpreview.LinkPreviewRepository import org.thoughtcrime.securesms.linkpreview.LinkPreviewRepository
import org.thoughtcrime.securesms.linkpreview.LinkPreviewUtil import org.thoughtcrime.securesms.linkpreview.LinkPreviewUtil
import org.thoughtcrime.securesms.mms.OutgoingMediaMessage import org.thoughtcrime.securesms.mms.OutgoingMediaMessage
import org.thoughtcrime.securesms.mms.QuoteModel
import org.thoughtcrime.securesms.recipients.Recipient import org.thoughtcrime.securesms.recipients.Recipient
import org.thoughtcrime.securesms.util.GroupUtil import org.thoughtcrime.securesms.util.GroupUtil
import org.thoughtcrime.securesms.util.TextSecurePreferences 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.LokiGroupChat
import org.whispersystems.signalservice.loki.api.LokiGroupChatAPI import org.whispersystems.signalservice.loki.api.LokiGroupChatAPI
import org.whispersystems.signalservice.loki.api.LokiGroupMessage import org.whispersystems.signalservice.loki.api.LokiGroupMessage
import java.util.*
class LokiGroupChatPoller(private val context: Context, private val group: LokiGroupChat) { class LokiGroupChatPoller(private val context: Context, private val group: LokiGroupChat) {
private val handler = Handler() private val handler = Handler()
@ -102,11 +97,21 @@ class LokiGroupChatPoller(private val context: Context, private val group: LokiG
fun processIncomingMessage(message: LokiGroupMessage) { fun processIncomingMessage(message: LokiGroupMessage) {
val id = group.id.toByteArray() val id = group.id.toByteArray()
val x1 = SignalServiceGroup(SignalServiceGroup.Type.UPDATE, id, null, null, null) 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 x3 = SignalServiceContent(x2, message.hexEncodedPublicKey, SignalServiceAddress.DEFAULT_DEVICE_ID, message.timestamp, false)
val senderDisplayName = "${message.displayName} (...${message.hexEncodedPublicKey.takeLast(8)})" val senderDisplayName = "${message.displayName} (...${message.hexEncodedPublicKey.takeLast(8)})"
DatabaseFactory.getLokiUserDatabase(context).setServerDisplayName(group.id, message.hexEncodedPublicKey, senderDisplayName) 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) { fun processOutgoingMessage(message: LokiGroupMessage) {
val messageServerID = message.serverID ?: return 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 id = group.id.toByteArray()
val mmsDatabase = DatabaseFactory.getMmsDatabase(context) val mmsDatabase = DatabaseFactory.getMmsDatabase(context)
val recipient = Recipient.from(context, Address.fromSerialized(GroupUtil.getEncodedId(id, false)), false) val recipient = Recipient.from(context, Address.fromSerialized(GroupUtil.getEncodedId(id, false)), false)
val signalMessage = OutgoingMediaMessage(recipient, message.body, ArrayList<Attachment>(), message.timestamp, 0, 0, ThreadDatabase.DistributionTypes.DEFAULT, val quote: QuoteModel?
null, ArrayList<Contact>(), ArrayList<LinkPreview>(), ArrayList<NetworkFailure>(), ArrayList<IdentityKeyMismatch>()) 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) val threadID = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipient)
fun finalize() { fun finalize() {
val messageID = mmsDatabase.insertMessageOutbox(signalMessage, threadID, false, null) val messageID = mmsDatabase.insertMessageOutbox(signalMessage, threadID, false, null)