diff --git a/res/layout/conversation_activity.xml b/res/layout/conversation_activity.xml
index ef3ca408a1..11b797760d 100644
--- a/res/layout/conversation_activity.xml
+++ b/res/layout/conversation_activity.xml
@@ -51,12 +51,10 @@
android:inflatedId="@+id/unverified_banner"
android:layout="@layout/conversation_activity_unverified_banner_stub" />
-
+ android:layout_height="wrap_content" />
-
-
@@ -48,7 +33,8 @@
android:id="@+id/dismissButton"
style="@style/Widget.AppCompat.Button.Borderless"
android:layout_width="wrap_content"
- android:layout_height="36dp"
+ android:layout_height="wrap_content"
+ android:gravity="center"
android:text="@string/session_restore_banner_dismiss_button_title" />
diff --git a/src/org/thoughtcrime/securesms/conversation/ConversationActivity.java b/src/org/thoughtcrime/securesms/conversation/ConversationActivity.java
index 8de7cc8653..16641984dd 100644
--- a/src/org/thoughtcrime/securesms/conversation/ConversationActivity.java
+++ b/src/org/thoughtcrime/securesms/conversation/ConversationActivity.java
@@ -359,7 +359,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
private boolean isFriendsWithAnyDevice = false;
// Restoration
- protected Stub sessionRestoreBannerView;
+ protected SessionRestoreBannerView sessionRestoreBannerView;
@Override
protected void onPreCreate() {
@@ -428,6 +428,17 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
}
});
+ sessionRestoreBannerView.setOnRestore(() -> {
+ this.restoreSession();
+ return Unit.INSTANCE;
+ });
+ sessionRestoreBannerView.setOnDismiss(() -> {
+ // TODO: Maybe silence for x minutes?
+ DatabaseFactory.getLokiThreadDatabase(ConversationActivity.this).removeAllSessionRestoreDevices(threadId);
+ updateSessionRestoreBanner();
+ return Unit.INSTANCE;
+ });
+
LokiAPIUtilities.INSTANCE.populateUserHexEncodedPublicKeyCacheIfNeeded(threadId, this);
if (this.recipient.isGroupRecipient()) {
@@ -496,6 +507,8 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
DatabaseFactory.getLokiThreadDatabase(this).setDelegate(this);
updateInputPanel();
+ updateSessionRestoreBanner();
+
Log.i(TAG, "onResume() Finished: " + (System.currentTimeMillis() - getIntent().getLongExtra(TIMING_EXTRA, 0)));
}
@@ -1496,11 +1509,11 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
protected void updateSessionRestoreBanner() {
Set devices = DatabaseFactory.getLokiThreadDatabase(this).getSessionRestoreDevices(threadId);
- SessionRestoreBannerView view = sessionRestoreBannerView.get();
if (devices.size() > 0) {
- view.show();
+ sessionRestoreBannerView.update(recipient);
+ sessionRestoreBannerView.show();
} else {
- view.hide();
+ sessionRestoreBannerView.hide();
}
}
@@ -1600,18 +1613,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
inputPanel = ViewUtil.findById(this, R.id.bottom_panel);
searchNav = ViewUtil.findById(this, R.id.conversation_search_nav);
mentionCandidateSelectionView = ViewUtil.findById(this, R.id.userSelectionView);
- sessionRestoreBannerView = ViewUtil.findStubById(this, R.id.session_restore_banner_stub);
- sessionRestoreBannerView.get().setRecipient(recipient);
- sessionRestoreBannerView.get().setOnRestore(() -> {
- this.restoreSession();
- return Unit.INSTANCE;
- });
- sessionRestoreBannerView.get().setOnDismiss(() -> {
- // TODO: Maybe silence for x minutes?
- // TODO: Remove devices?
- sessionRestoreBannerView.get().hide();
- return Unit.INSTANCE;
- });
+ sessionRestoreBannerView = ViewUtil.findById(this, R.id.sessionRestoreBannerView);
ImageButton quickCameraToggle = ViewUtil.findById(this, R.id.quick_camera_toggle);
ImageButton inlineAttachmentButton = ViewUtil.findById(this, R.id.inline_attachment_button);
@@ -2233,7 +2235,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
@Override
public void handleSessionRestoreDevicesChanged(long threadId) {
if (threadId == this.threadId) {
- updateSessionRestoreBanner();
+ runOnUiThread(this::updateSessionRestoreBanner);
}
}
diff --git a/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java b/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java
index 06b902f3a3..d140c8bf8d 100644
--- a/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java
+++ b/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java
@@ -58,6 +58,7 @@ import org.thoughtcrime.securesms.database.StickerDatabase;
import org.thoughtcrime.securesms.database.ThreadDatabase;
import org.thoughtcrime.securesms.database.model.MessageRecord;
import org.thoughtcrime.securesms.database.model.MmsMessageRecord;
+import org.thoughtcrime.securesms.database.model.SmsMessageRecord;
import org.thoughtcrime.securesms.database.model.StickerRecord;
import org.thoughtcrime.securesms.dependencies.InjectableType;
import org.thoughtcrime.securesms.groups.GroupMessageProcessor;
@@ -275,11 +276,9 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
LokiServiceCipher cipher = new LokiServiceCipher(localAddress, axolotlStore, lokiThreadDatabase, lokiPreKeyRecordDatabase, UnidentifiedAccessUtil.getCertificateValidator());
// Loki - Handle session reset logic
- /*
if (!envelope.isFriendRequest() && cipher.getSessionStatus(envelope) == null && envelope.isPreKeySignalMessage()) {
cipher.validateBackgroundMessage(envelope, envelope.getContent());
}
- */
// Loki - Ignore any friend requests that we got before restoration
if (envelope.isFriendRequest() && envelope.getTimestamp() < TextSecurePreferences.getRestorationTime(context)) {
@@ -1385,17 +1384,39 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
}
}
+ private SmsMessageRecord getLastMessage(String sender) {
+ try {
+ SmsDatabase smsDatabase = DatabaseFactory.getSmsDatabase(context);
+ Recipient recipient = Recipient.from(context, Address.fromSerialized(sender), false);
+ long threadID = DatabaseFactory.getThreadDatabase(context).getThreadIdIfExistsFor(recipient);
+ if (threadID < 0) {
+ return null;
+ }
+ int messageCount = smsDatabase.getMessageCountForThread(threadID);
+ if (messageCount <= 0) {
+ return null;
+ }
+ long lastMessageID = smsDatabase.getIDForMessageAtIndex(threadID, messageCount - 1);
+ return smsDatabase.getMessage(lastMessageID);
+ } catch (Exception e) {
+ return null;
+ }
+ }
+
private void handleCorruptMessage(@NonNull String sender, int senderDevice, long timestamp,
@NonNull Optional smsMessageId)
{
SmsDatabase smsDatabase = DatabaseFactory.getSmsDatabase(context);
if (!smsMessageId.isPresent()) {
- Optional insertResult = insertPlaceholder(sender, senderDevice, timestamp);
+ SmsMessageRecord lastMessage = getLastMessage(sender);
+ if (lastMessage == null || !SmsDatabase.Types.isFailedDecryptType(lastMessage.getType())) {
+ Optional insertResult = insertPlaceholder(sender, senderDevice, timestamp);
- if (insertResult.isPresent()) {
- smsDatabase.markAsDecryptFailed(insertResult.get().getMessageId());
- // MessageNotifier.updateNotification(context, insertResult.get().getThreadId());
+ if (insertResult.isPresent()) {
+ smsDatabase.markAsDecryptFailed(insertResult.get().getMessageId());
+ MessageNotifier.updateNotification(context, insertResult.get().getThreadId());
+ }
}
} else {
smsDatabase.markAsDecryptFailed(smsMessageId.get());
@@ -1409,11 +1430,14 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
SmsDatabase smsDatabase = DatabaseFactory.getSmsDatabase(context);
if (!smsMessageId.isPresent()) {
- Optional insertResult = insertPlaceholder(sender, senderDevice, timestamp);
+ SmsMessageRecord lastMessage = getLastMessage(sender);
+ if (lastMessage == null || !SmsDatabase.Types.isNoRemoteSessionType(lastMessage.getType())) {
+ Optional insertResult = insertPlaceholder(sender, senderDevice, timestamp);
- if (insertResult.isPresent()) {
- smsDatabase.markAsNoSession(insertResult.get().getMessageId());
- // MessageNotifier.updateNotification(context, insertResult.get().getThreadId());
+ if (insertResult.isPresent()) {
+ smsDatabase.markAsNoSession(insertResult.get().getMessageId());
+ MessageNotifier.updateNotification(context, insertResult.get().getThreadId());
+ }
}
} else {
smsDatabase.markAsNoSession(smsMessageId.get());
diff --git a/src/org/thoughtcrime/securesms/loki/LokiThreadDatabase.kt b/src/org/thoughtcrime/securesms/loki/LokiThreadDatabase.kt
index d98ca1603f..dfc732474c 100644
--- a/src/org/thoughtcrime/securesms/loki/LokiThreadDatabase.kt
+++ b/src/org/thoughtcrime/securesms/loki/LokiThreadDatabase.kt
@@ -14,6 +14,7 @@ import org.whispersystems.signalservice.loki.api.LokiPublicChat
import org.whispersystems.signalservice.loki.messaging.LokiThreadDatabaseProtocol
import org.whispersystems.signalservice.loki.messaging.LokiThreadFriendRequestStatus
import org.whispersystems.signalservice.loki.messaging.LokiThreadSessionResetStatus
+import org.whispersystems.signalservice.loki.utilities.PublicKeyValidation
class LokiThreadDatabase(context: Context, helper: SQLCipherOpenHelper) : Database(context, helper), LokiThreadDatabaseProtocol {
var delegate: LokiThreadDatabaseDelegate? = null
@@ -152,7 +153,10 @@ class LokiThreadDatabase(context: Context, helper: SQLCipherOpenHelper) : Databa
}
fun getSessionRestoreDevices(threadID: Long): Set {
- return TextSecurePreferences.getStringPreference(context, "session_restore_devices_$threadID", "").split(",").toSet()
+ return TextSecurePreferences.getStringPreference(context, "session_restore_devices_$threadID", "")
+ .split(",")
+ .filter { PublicKeyValidation.isValid(it) }
+ .toSet()
}
fun removeAllSessionRestoreDevices(threadID: Long) {
diff --git a/src/org/thoughtcrime/securesms/loki/SessionRestoreBannerView.kt b/src/org/thoughtcrime/securesms/loki/SessionRestoreBannerView.kt
index 862360cdba..c14c64c3d4 100644
--- a/src/org/thoughtcrime/securesms/loki/SessionRestoreBannerView.kt
+++ b/src/org/thoughtcrime/securesms/loki/SessionRestoreBannerView.kt
@@ -1,38 +1,27 @@
package org.thoughtcrime.securesms.loki
-import org.thoughtcrime.securesms.components.reminder.Reminder
-
-import android.annotation.TargetApi
import android.content.Context
-import android.os.Build.VERSION_CODES
-import android.text.TextUtils
import android.util.AttributeSet
import android.view.LayoutInflater
import android.view.View
-import android.view.ViewGroup
-import android.widget.ImageButton
import android.widget.LinearLayout
-import android.widget.TextView
import kotlinx.android.synthetic.main.session_restore_banner.view.*
import network.loki.messenger.R
import org.thoughtcrime.securesms.recipients.Recipient
-import org.thoughtcrime.securesms.util.ViewUtil
/**
* View to display actionable reminders to the user
*/
-class SessionRestoreBannerView private constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : LinearLayout(context, attrs, defStyleAttr) {
- private var container: ViewGroup? = null
- private var closeButton: ImageButton? = null
- private var title: TextView? = null
- private var text: TextView? = null
+class SessionRestoreBannerView(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : LinearLayout(context, attrs, defStyleAttr) {
lateinit var recipient: Recipient
var onDismiss: (() -> Unit)? = null
var onRestore: (() -> Unit)? = null
+ // region Initialization
+ constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0)
constructor(context: Context) : this(context, null)
- private constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0)
+ // endregion
init {
LayoutInflater.from(context).inflate(R.layout.session_restore_banner, this, true)
@@ -46,10 +35,10 @@ class SessionRestoreBannerView private constructor(context: Context, attrs: Attr
}
fun show() {
- container!!.visibility = View.VISIBLE;
+ sessionRestoreBanner.visibility = View.VISIBLE
}
fun hide() {
- container!!.visibility = View.GONE
+ sessionRestoreBanner.visibility = View.GONE
}
}