Fix banner display

This commit is contained in:
Mikunj 2019-12-06 16:33:17 +11:00
parent 97ffea040f
commit b44ff69d8d
6 changed files with 76 additions and 72 deletions

View File

@ -51,12 +51,10 @@
android:inflatedId="@+id/unverified_banner" android:inflatedId="@+id/unverified_banner"
android:layout="@layout/conversation_activity_unverified_banner_stub" /> android:layout="@layout/conversation_activity_unverified_banner_stub" />
<ViewStub <org.thoughtcrime.securesms.loki.SessionRestoreBannerView
android:id="@+id/session_restore_banner_stub" android:id="@+id/sessionRestoreBannerView"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content" />
android:inflatedId="@+id/session_restore_banner"
android:layout="@layout/conversation_activity_unverified_banner_stub" />
<ViewStub <ViewStub
android:id="@+id/reminder_stub" android:id="@+id/reminder_stub"

View File

@ -1,31 +1,17 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/session_restore_banner" android:id="@+id/sessionRestoreBanner"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:background="@color/core_grey_60" android:background="@color/core_grey_60"
android:focusable="true"
android:nextFocusDown="@+id/cancel"
android:orientation="vertical" android:orientation="vertical"
android:paddingStart="8dp" android:paddingLeft="8dp"
android:paddingTop="24dp" android:paddingTop="8dp"
android:paddingEnd="8dp" android:paddingRight="8dp"
android:paddingBottom="8dp" android:visibility="visible"
android:visibility="gone"
tools:visibility="visible"> tools:visibility="visible">
<TextView
android:id="@+id/restoreTitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="4dp"
android:textColor="@color/white"
android:textSize="18sp"
tools:text="@string/session_restore_banner_title" />
<TextView <TextView
android:id="@+id/restoreText" android:id="@+id/restoreText"
android:layout_width="match_parent" android:layout_width="match_parent"
@ -40,7 +26,6 @@
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:gravity="right" android:gravity="right"
android:orientation="horizontal"> android:orientation="horizontal">
@ -48,7 +33,8 @@
android:id="@+id/dismissButton" android:id="@+id/dismissButton"
style="@style/Widget.AppCompat.Button.Borderless" style="@style/Widget.AppCompat.Button.Borderless"
android:layout_width="wrap_content" 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" /> android:text="@string/session_restore_banner_dismiss_button_title" />
<android.support.v4.widget.Space <android.support.v4.widget.Space
@ -59,7 +45,8 @@
android:id="@+id/restoreButton" android:id="@+id/restoreButton"
style="@style/Button.Borderless" style="@style/Button.Borderless"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="36dp" android:layout_height="wrap_content"
android:gravity="center"
android:text="@string/session_restore_banner_restore_button_title" /> android:text="@string/session_restore_banner_restore_button_title" />
</LinearLayout> </LinearLayout>

View File

@ -359,7 +359,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
private boolean isFriendsWithAnyDevice = false; private boolean isFriendsWithAnyDevice = false;
// Restoration // Restoration
protected Stub<SessionRestoreBannerView> sessionRestoreBannerView; protected SessionRestoreBannerView sessionRestoreBannerView;
@Override @Override
protected void onPreCreate() { 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); LokiAPIUtilities.INSTANCE.populateUserHexEncodedPublicKeyCacheIfNeeded(threadId, this);
if (this.recipient.isGroupRecipient()) { if (this.recipient.isGroupRecipient()) {
@ -496,6 +507,8 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
DatabaseFactory.getLokiThreadDatabase(this).setDelegate(this); DatabaseFactory.getLokiThreadDatabase(this).setDelegate(this);
updateInputPanel(); updateInputPanel();
updateSessionRestoreBanner();
Log.i(TAG, "onResume() Finished: " + (System.currentTimeMillis() - getIntent().getLongExtra(TIMING_EXTRA, 0))); Log.i(TAG, "onResume() Finished: " + (System.currentTimeMillis() - getIntent().getLongExtra(TIMING_EXTRA, 0)));
} }
@ -1496,11 +1509,11 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
protected void updateSessionRestoreBanner() { protected void updateSessionRestoreBanner() {
Set<String> devices = DatabaseFactory.getLokiThreadDatabase(this).getSessionRestoreDevices(threadId); Set<String> devices = DatabaseFactory.getLokiThreadDatabase(this).getSessionRestoreDevices(threadId);
SessionRestoreBannerView view = sessionRestoreBannerView.get();
if (devices.size() > 0) { if (devices.size() > 0) {
view.show(); sessionRestoreBannerView.update(recipient);
sessionRestoreBannerView.show();
} else { } else {
view.hide(); sessionRestoreBannerView.hide();
} }
} }
@ -1600,18 +1613,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
inputPanel = ViewUtil.findById(this, R.id.bottom_panel); inputPanel = ViewUtil.findById(this, R.id.bottom_panel);
searchNav = ViewUtil.findById(this, R.id.conversation_search_nav); searchNav = ViewUtil.findById(this, R.id.conversation_search_nav);
mentionCandidateSelectionView = ViewUtil.findById(this, R.id.userSelectionView); mentionCandidateSelectionView = ViewUtil.findById(this, R.id.userSelectionView);
sessionRestoreBannerView = ViewUtil.findStubById(this, R.id.session_restore_banner_stub); sessionRestoreBannerView = ViewUtil.findById(this, R.id.sessionRestoreBannerView);
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;
});
ImageButton quickCameraToggle = ViewUtil.findById(this, R.id.quick_camera_toggle); ImageButton quickCameraToggle = ViewUtil.findById(this, R.id.quick_camera_toggle);
ImageButton inlineAttachmentButton = ViewUtil.findById(this, R.id.inline_attachment_button); ImageButton inlineAttachmentButton = ViewUtil.findById(this, R.id.inline_attachment_button);
@ -2233,7 +2235,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
@Override @Override
public void handleSessionRestoreDevicesChanged(long threadId) { public void handleSessionRestoreDevicesChanged(long threadId) {
if (threadId == this.threadId) { if (threadId == this.threadId) {
updateSessionRestoreBanner(); runOnUiThread(this::updateSessionRestoreBanner);
} }
} }

View File

@ -58,6 +58,7 @@ import org.thoughtcrime.securesms.database.StickerDatabase;
import org.thoughtcrime.securesms.database.ThreadDatabase; import org.thoughtcrime.securesms.database.ThreadDatabase;
import org.thoughtcrime.securesms.database.model.MessageRecord; import org.thoughtcrime.securesms.database.model.MessageRecord;
import org.thoughtcrime.securesms.database.model.MmsMessageRecord; 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.database.model.StickerRecord;
import org.thoughtcrime.securesms.dependencies.InjectableType; import org.thoughtcrime.securesms.dependencies.InjectableType;
import org.thoughtcrime.securesms.groups.GroupMessageProcessor; 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()); LokiServiceCipher cipher = new LokiServiceCipher(localAddress, axolotlStore, lokiThreadDatabase, lokiPreKeyRecordDatabase, UnidentifiedAccessUtil.getCertificateValidator());
// Loki - Handle session reset logic // Loki - Handle session reset logic
/*
if (!envelope.isFriendRequest() && cipher.getSessionStatus(envelope) == null && envelope.isPreKeySignalMessage()) { if (!envelope.isFriendRequest() && cipher.getSessionStatus(envelope) == null && envelope.isPreKeySignalMessage()) {
cipher.validateBackgroundMessage(envelope, envelope.getContent()); cipher.validateBackgroundMessage(envelope, envelope.getContent());
} }
*/
// Loki - Ignore any friend requests that we got before restoration // Loki - Ignore any friend requests that we got before restoration
if (envelope.isFriendRequest() && envelope.getTimestamp() < TextSecurePreferences.getRestorationTime(context)) { 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, private void handleCorruptMessage(@NonNull String sender, int senderDevice, long timestamp,
@NonNull Optional<Long> smsMessageId) @NonNull Optional<Long> smsMessageId)
{ {
SmsDatabase smsDatabase = DatabaseFactory.getSmsDatabase(context); SmsDatabase smsDatabase = DatabaseFactory.getSmsDatabase(context);
if (!smsMessageId.isPresent()) { if (!smsMessageId.isPresent()) {
Optional<InsertResult> insertResult = insertPlaceholder(sender, senderDevice, timestamp); SmsMessageRecord lastMessage = getLastMessage(sender);
if (lastMessage == null || !SmsDatabase.Types.isFailedDecryptType(lastMessage.getType())) {
Optional<InsertResult> insertResult = insertPlaceholder(sender, senderDevice, timestamp);
if (insertResult.isPresent()) { if (insertResult.isPresent()) {
smsDatabase.markAsDecryptFailed(insertResult.get().getMessageId()); smsDatabase.markAsDecryptFailed(insertResult.get().getMessageId());
// MessageNotifier.updateNotification(context, insertResult.get().getThreadId()); MessageNotifier.updateNotification(context, insertResult.get().getThreadId());
}
} }
} else { } else {
smsDatabase.markAsDecryptFailed(smsMessageId.get()); smsDatabase.markAsDecryptFailed(smsMessageId.get());
@ -1409,11 +1430,14 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
SmsDatabase smsDatabase = DatabaseFactory.getSmsDatabase(context); SmsDatabase smsDatabase = DatabaseFactory.getSmsDatabase(context);
if (!smsMessageId.isPresent()) { if (!smsMessageId.isPresent()) {
Optional<InsertResult> insertResult = insertPlaceholder(sender, senderDevice, timestamp); SmsMessageRecord lastMessage = getLastMessage(sender);
if (lastMessage == null || !SmsDatabase.Types.isNoRemoteSessionType(lastMessage.getType())) {
Optional<InsertResult> insertResult = insertPlaceholder(sender, senderDevice, timestamp);
if (insertResult.isPresent()) { if (insertResult.isPresent()) {
smsDatabase.markAsNoSession(insertResult.get().getMessageId()); smsDatabase.markAsNoSession(insertResult.get().getMessageId());
// MessageNotifier.updateNotification(context, insertResult.get().getThreadId()); MessageNotifier.updateNotification(context, insertResult.get().getThreadId());
}
} }
} else { } else {
smsDatabase.markAsNoSession(smsMessageId.get()); smsDatabase.markAsNoSession(smsMessageId.get());

View File

@ -14,6 +14,7 @@ import org.whispersystems.signalservice.loki.api.LokiPublicChat
import org.whispersystems.signalservice.loki.messaging.LokiThreadDatabaseProtocol import org.whispersystems.signalservice.loki.messaging.LokiThreadDatabaseProtocol
import org.whispersystems.signalservice.loki.messaging.LokiThreadFriendRequestStatus import org.whispersystems.signalservice.loki.messaging.LokiThreadFriendRequestStatus
import org.whispersystems.signalservice.loki.messaging.LokiThreadSessionResetStatus import org.whispersystems.signalservice.loki.messaging.LokiThreadSessionResetStatus
import org.whispersystems.signalservice.loki.utilities.PublicKeyValidation
class LokiThreadDatabase(context: Context, helper: SQLCipherOpenHelper) : Database(context, helper), LokiThreadDatabaseProtocol { class LokiThreadDatabase(context: Context, helper: SQLCipherOpenHelper) : Database(context, helper), LokiThreadDatabaseProtocol {
var delegate: LokiThreadDatabaseDelegate? = null var delegate: LokiThreadDatabaseDelegate? = null
@ -152,7 +153,10 @@ class LokiThreadDatabase(context: Context, helper: SQLCipherOpenHelper) : Databa
} }
fun getSessionRestoreDevices(threadID: Long): Set<String> { fun getSessionRestoreDevices(threadID: Long): Set<String> {
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) { fun removeAllSessionRestoreDevices(threadID: Long) {

View File

@ -1,38 +1,27 @@
package org.thoughtcrime.securesms.loki package org.thoughtcrime.securesms.loki
import org.thoughtcrime.securesms.components.reminder.Reminder
import android.annotation.TargetApi
import android.content.Context import android.content.Context
import android.os.Build.VERSION_CODES
import android.text.TextUtils
import android.util.AttributeSet import android.util.AttributeSet
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup
import android.widget.ImageButton
import android.widget.LinearLayout import android.widget.LinearLayout
import android.widget.TextView
import kotlinx.android.synthetic.main.session_restore_banner.view.* import kotlinx.android.synthetic.main.session_restore_banner.view.*
import network.loki.messenger.R import network.loki.messenger.R
import org.thoughtcrime.securesms.recipients.Recipient import org.thoughtcrime.securesms.recipients.Recipient
import org.thoughtcrime.securesms.util.ViewUtil
/** /**
* View to display actionable reminders to the user * View to display actionable reminders to the user
*/ */
class SessionRestoreBannerView private constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : LinearLayout(context, attrs, defStyleAttr) { class SessionRestoreBannerView(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
lateinit var recipient: Recipient lateinit var recipient: Recipient
var onDismiss: (() -> Unit)? = null var onDismiss: (() -> Unit)? = null
var onRestore: (() -> Unit)? = null var onRestore: (() -> Unit)? = null
// region Initialization
constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0)
constructor(context: Context) : this(context, null) constructor(context: Context) : this(context, null)
private constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0) // endregion
init { init {
LayoutInflater.from(context).inflate(R.layout.session_restore_banner, this, true) 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() { fun show() {
container!!.visibility = View.VISIBLE; sessionRestoreBanner.visibility = View.VISIBLE
} }
fun hide() { fun hide() {
container!!.visibility = View.GONE sessionRestoreBanner.visibility = View.GONE
} }
} }