Move session restore prompt from message level to conversation level.

This commit is contained in:
Mikunj 2019-12-06 13:00:08 +11:00
parent 0caeb3a109
commit 97ffea040f
20 changed files with 232 additions and 124 deletions

View file

@ -51,6 +51,13 @@
android:inflatedId="@+id/unverified_banner"
android:layout="@layout/conversation_activity_unverified_banner_stub" />
<ViewStub
android:id="@+id/session_restore_banner_stub"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inflatedId="@+id/session_restore_banner"
android:layout="@layout/conversation_activity_unverified_banner_stub" />
<ViewStub
android:id="@+id/reminder_stub"
android:layout_width="match_parent"

View file

@ -74,15 +74,6 @@
android:textColor="?conversation_item_update_text_color"
tools:text="30 min ago" />
<Button
android:id="@+id/conversation_update_button"
style="@style/Button.Borderless"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="Button"
android:visibility="gone" />
</LinearLayout>
</org.thoughtcrime.securesms.conversation.ConversationUpdateItem>

View file

@ -0,0 +1,66 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/session_restore_banner"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/core_grey_60"
android:focusable="true"
android:nextFocusDown="@+id/cancel"
android:orientation="vertical"
android:paddingStart="8dp"
android:paddingTop="24dp"
android:paddingEnd="8dp"
android:paddingBottom="8dp"
android:visibility="gone"
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
android:id="@+id/restoreText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:fontFamily="sans-serif-light"
android:textColor="@color/white"
android:textSize="16sp"
tools:text="@string/session_restore_banner_message" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:gravity="right"
android:orientation="horizontal">
<Button
android:id="@+id/dismissButton"
style="@style/Widget.AppCompat.Button.Borderless"
android:layout_width="wrap_content"
android:layout_height="36dp"
android:text="@string/session_restore_banner_dismiss_button_title" />
<android.support.v4.widget.Space
android:layout_width="8dp"
android:layout_height="wrap_content" />
<Button
android:id="@+id/restoreButton"
style="@style/Button.Borderless"
android:layout_width="wrap_content"
android:layout_height="36dp"
android:text="@string/session_restore_banner_restore_button_title" />
</LinearLayout>
</LinearLayout>

View file

@ -735,9 +735,7 @@
<!-- MessageDisplayHelper -->
<string name="MessageDisplayHelper_bad_encrypted_message">Bad encrypted message</string>
<string name="MessageDisplayHelper_message_encrypted_for_non_existing_session">Message encrypted for non-existing session</string>
<string name="MessageRecord_session_restore_required">Could not decrypt an incoming message. Would you like to start a new session with %s?</string>
<string name="MessageRecord_session_restore_sent">You have sent a session restore request to %s</string>
<string name="MessageRecord_session_restore_button_title">Restore session</string>
<!-- MmsMessageRecord -->
<string name="MmsMessageRecord_bad_encrypted_mms_message">Bad encrypted MMS message</string>
@ -1654,5 +1652,9 @@
<!-- Device unlink dialog -->
<string name="dialog_device_unlink_title">Device unlinked</string>
<string name="dialog_device_unlink_message">This device has been successfully unlinked</string>
<!-- Session restore banner -->
<string name="session_restore_banner_title">Could not decrypt an incoming message.</string>
<string name="session_restore_banner_message">Would you like to start a new session with %s?</string>
<string name="session_restore_banner_restore_button_title">Restore session</string>
<string name="session_restore_banner_dismiss_button_title">Dismiss</string>
</resources>

View file

@ -139,6 +139,7 @@ import org.thoughtcrime.securesms.database.MessagingDatabase.MarkedMessageInfo;
import org.thoughtcrime.securesms.database.MmsSmsColumns.Types;
import org.thoughtcrime.securesms.database.RecipientDatabase;
import org.thoughtcrime.securesms.database.RecipientDatabase.RegisteredState;
import org.thoughtcrime.securesms.database.SmsDatabase;
import org.thoughtcrime.securesms.database.ThreadDatabase;
import org.thoughtcrime.securesms.database.identity.IdentityRecordList;
import org.thoughtcrime.securesms.database.model.MessageRecord;
@ -154,7 +155,6 @@ import org.thoughtcrime.securesms.linkpreview.LinkPreviewRepository;
import org.thoughtcrime.securesms.linkpreview.LinkPreviewUtil;
import org.thoughtcrime.securesms.linkpreview.LinkPreviewViewModel;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.loki.ConversationUpdateItemViewDelegate;
import org.thoughtcrime.securesms.loki.FriendRequestViewDelegate;
import org.thoughtcrime.securesms.loki.LokiAPIUtilities;
import org.thoughtcrime.securesms.loki.LokiThreadDatabase;
@ -163,6 +163,7 @@ import org.thoughtcrime.securesms.loki.LokiThreadDatabaseDelegate;
import org.thoughtcrime.securesms.loki.LokiUserDatabase;
import org.thoughtcrime.securesms.loki.MentionCandidateSelectionView;
import org.thoughtcrime.securesms.loki.MultiDeviceUtilities;
import org.thoughtcrime.securesms.loki.SessionRestoreBannerView;
import org.thoughtcrime.securesms.mediasend.Media;
import org.thoughtcrime.securesms.mediasend.MediaSendActivity;
import org.thoughtcrime.securesms.mms.AttachmentManager;
@ -242,6 +243,7 @@ import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
@ -249,7 +251,6 @@ import java.util.concurrent.atomic.AtomicInteger;
import kotlin.Unit;
import network.loki.messenger.R;
import static nl.komponents.kovenant.KovenantApi.task;
import static org.thoughtcrime.securesms.TransportOption.Type;
import static org.thoughtcrime.securesms.database.GroupDatabase.GroupRecord;
import static org.whispersystems.libsignal.SessionCipher.SESSION_LOCK;
@ -273,8 +274,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
ConversationSearchBottomBar.EventListener,
StickerKeyboardProvider.StickerEventListener,
LokiThreadDatabaseDelegate,
FriendRequestViewDelegate,
ConversationUpdateItemViewDelegate
FriendRequestViewDelegate
{
private static final String TAG = ConversationActivity.class.getSimpleName();
@ -358,6 +358,9 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
// Multi Device
private boolean isFriendsWithAnyDevice = false;
// Restoration
protected Stub<SessionRestoreBannerView> sessionRestoreBannerView;
@Override
protected void onPreCreate() {
dynamicTheme.onCreate(this);
@ -378,7 +381,6 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
fragment = initFragment(R.id.fragment_content, new ConversationFragment(), dynamicLanguage.getCurrentLocale());
fragment.friendRequestViewDelegate = this;
fragment.conversationUpdateItemViewDelegate = this;
initializeReceivers();
initializeActionBar();
@ -1492,6 +1494,16 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
}
}
protected void updateSessionRestoreBanner() {
Set<String> devices = DatabaseFactory.getLokiThreadDatabase(this).getSessionRestoreDevices(threadId);
SessionRestoreBannerView view = sessionRestoreBannerView.get();
if (devices.size() > 0) {
view.show();
} else {
view.hide();
}
}
private void updateDefaultSubscriptionId(Optional<Integer> defaultSubscriptionId) {
Log.i(TAG, "updateDefaultSubscriptionId(" + defaultSubscriptionId.orNull() + ")");
sendButton.setDefaultSubscriptionId(defaultSubscriptionId);
@ -1588,6 +1600,18 @@ 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;
});
ImageButton quickCameraToggle = ViewUtil.findById(this, R.id.quick_camera_toggle);
ImageButton inlineAttachmentButton = ViewUtil.findById(this, R.id.inline_attachment_button);
@ -2206,6 +2230,13 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
this.updateInputPanel();
}
@Override
public void handleSessionRestoreDevicesChanged(long threadId) {
if (threadId == this.threadId) {
updateSessionRestoreBanner();
}
}
private void updateInputPanel() {
/*
isFriendsWithAnyDevice caches whether we are friends with any of the other users device.
@ -3083,14 +3114,19 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
}
// endregion
@Override
public void updateItemButtonPressed(@NonNull MessageRecord messageRecord) {
public void restoreSession() {
// Loki - User clicked restore session
Recipient recipient = messageRecord.getRecipient();
if (!recipient.isGroupRecipient() && messageRecord.isNoRemoteSession() && !messageRecord.isLokiSessionRestoreSent()) {
MessageSender.sendRestoreSessionMessage(this, recipient.getAddress().serialize());
DatabaseFactory.getSmsDatabase(this).markAsLokiSessionRestoreSent(messageRecord.id);
TextSecurePreferences.setShowingSessionRestorePrompt(this, messageRecord.getIndividualRecipient().getAddress().serialize(), false);
if (!recipient.isGroupRecipient()) {
LokiThreadDatabase lokiThreadDatabase = DatabaseFactory.getLokiThreadDatabase(this);
SmsDatabase database = DatabaseFactory.getSmsDatabase(this);
Set<String> devices = lokiThreadDatabase.getSessionRestoreDevices(threadId);
for (String device : devices) { MessageSender.sendRestoreSessionMessage(this, device); }
long messageId = database.insertMessageOutbox(threadId, new OutgoingTextMessage(recipient,"", 0, 0), false, System.currentTimeMillis(), null);
if (messageId > -1) {
database.markAsLokiSessionRestoreSent(messageId);
}
lokiThreadDatabase.removeAllSessionRestoreDevices(threadId);
updateSessionRestoreBanner();
}
}
}

View file

@ -41,7 +41,6 @@ import org.thoughtcrime.securesms.database.MmsSmsDatabase;
import org.thoughtcrime.securesms.database.model.MessageRecord;
import org.thoughtcrime.securesms.database.model.MmsMessageRecord;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.loki.ConversationUpdateItemViewDelegate;
import org.thoughtcrime.securesms.loki.FriendRequestViewDelegate;
import org.thoughtcrime.securesms.mms.GlideRequests;
import org.thoughtcrime.securesms.mms.SlideDeck;
@ -109,7 +108,6 @@ public class ConversationAdapter <V extends View & BindableConversationItem>
private String searchQuery;
public FriendRequestViewDelegate friendRequestViewDelegate; // Loki
public ConversationUpdateItemViewDelegate conversationUpdateItemViewDelegate;
protected static class ViewHolder extends RecyclerView.ViewHolder {
public <V extends View & BindableConversationItem> ViewHolder(final @NonNull V itemView) {
@ -206,9 +204,8 @@ public class ConversationAdapter <V extends View & BindableConversationItem>
BindableConversationItem conversationItem = viewHolder.getView();
if (conversationItem instanceof ConversationItem) {
((ConversationItem)conversationItem).friendRequestViewDelegate = this.friendRequestViewDelegate;
} else if (conversationItem instanceof ConversationUpdateItem) {
((ConversationUpdateItem)conversationItem).delegate = this.conversationUpdateItemViewDelegate;
}
conversationItem.bind(messageRecord,
Optional.fromNullable(previousRecord),
Optional.fromNullable(nextRecord),

View file

@ -79,7 +79,6 @@ import org.thoughtcrime.securesms.database.model.MmsMessageRecord;
import org.thoughtcrime.securesms.jobs.DirectoryRefreshJob;
import org.thoughtcrime.securesms.linkpreview.LinkPreview;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.loki.ConversationUpdateItemViewDelegate;
import org.thoughtcrime.securesms.loki.FriendRequestViewDelegate;
import org.thoughtcrime.securesms.longmessage.LongMessageActivity;
import org.thoughtcrime.securesms.mediasend.Media;
@ -153,7 +152,6 @@ public class ConversationFragment extends Fragment
private View scrollToBottomButton;
private TextView scrollDateHeader;
public FriendRequestViewDelegate friendRequestViewDelegate; // Loki
public ConversationUpdateItemViewDelegate conversationUpdateItemViewDelegate;
@Override
public void onCreate(Bundle icicle) {
@ -362,8 +360,7 @@ public class ConversationFragment extends Fragment
if (messageRecord.isGroupAction() || messageRecord.isCallLog() ||
messageRecord.isJoined() || messageRecord.isExpirationTimerUpdate() ||
messageRecord.isEndSession() || messageRecord.isIdentityUpdate() ||
messageRecord.isIdentityVerified() || messageRecord.isIdentityDefault() ||
messageRecord.isNoRemoteSession() || messageRecord.isLokiSessionRestoreSent())
messageRecord.isIdentityVerified() || messageRecord.isIdentityDefault() || messageRecord.isLokiSessionRestoreSent())
{
actionMessage = true;
}
@ -708,7 +705,6 @@ public class ConversationFragment extends Fragment
return;
}
adapter.friendRequestViewDelegate = this.friendRequestViewDelegate;
adapter.conversationUpdateItemViewDelegate = this.conversationUpdateItemViewDelegate;
if (cursor.getCount() >= PARTIAL_CONVERSATION_LIMIT && loader.hasLimit()) {
adapter.setFooterView(topLoadMoreView);

View file

@ -87,7 +87,6 @@ import org.thoughtcrime.securesms.jobs.SmsSendJob;
import org.thoughtcrime.securesms.linkpreview.LinkPreview;
import org.thoughtcrime.securesms.linkpreview.LinkPreviewUtil;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.loki.ConversationUpdateItemViewDelegate;
import org.thoughtcrime.securesms.loki.FriendRequestView;
import org.thoughtcrime.securesms.loki.FriendRequestViewDelegate;
import org.thoughtcrime.securesms.loki.LokiMessageDatabase;

View file

@ -9,7 +9,6 @@ import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
@ -22,7 +21,6 @@ import org.thoughtcrime.securesms.database.IdentityDatabase;
import org.thoughtcrime.securesms.database.IdentityDatabase.IdentityRecord;
import org.thoughtcrime.securesms.database.model.MessageRecord;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.loki.ConversationUpdateItemViewDelegate;
import org.thoughtcrime.securesms.mms.GlideRequests;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientModifiedListener;
@ -49,13 +47,10 @@ public class ConversationUpdateItem extends LinearLayout
private TextView title;
private TextView body;
private TextView date;
private Button button;
private Recipient sender;
private MessageRecord messageRecord;
private Locale locale;
public ConversationUpdateItemViewDelegate delegate;
public ConversationUpdateItem(Context context) {
super(context);
}
@ -72,12 +67,6 @@ public class ConversationUpdateItem extends LinearLayout
this.title = findViewById(R.id.conversation_update_title);
this.body = findViewById(R.id.conversation_update_body);
this.date = findViewById(R.id.conversation_update_date);
this.button = findViewById(R.id.conversation_update_button);
this.button.setOnClickListener(view -> {
if (delegate != null && messageRecord != null) {
delegate.updateItemButtonPressed(messageRecord);
}
});
this.setOnClickListener(new InternalClickListener(null));
}
@ -123,8 +112,7 @@ public class ConversationUpdateItem extends LinearLayout
else if (messageRecord.isIdentityUpdate()) setIdentityRecord(messageRecord);
else if (messageRecord.isIdentityVerified() ||
messageRecord.isIdentityDefault()) setIdentityVerifyUpdate(messageRecord);
else if (messageRecord.isNoRemoteSession() ||
messageRecord.isLokiSessionRestoreSent()) setTextMessageRecord(messageRecord);
else if (messageRecord.isLokiSessionRestoreSent()) setTextMessageRecord(messageRecord);
else throw new AssertionError("Neither group nor log nor joined.");
if (batchSelected.contains(messageRecord)) setSelected(true);
@ -217,12 +205,6 @@ public class ConversationUpdateItem extends LinearLayout
private void setTextMessageRecord(MessageRecord messageRecord) {
body.setText(messageRecord.getDisplayBody(getContext()));
if (messageRecord.isNoRemoteSession() && !messageRecord.isLokiSessionRestoreSent()) {
button.setVisibility(VISIBLE);
button.setText(R.string.MessageRecord_session_restore_button_title);
} else {
button.setVisibility(GONE);
}
icon.setVisibility(GONE);
title.setVisibility(GONE);

View file

@ -103,11 +103,7 @@ public abstract class DisplayRecord {
return SmsDatabase.Types.isKeyExchangeType(type);
}
public boolean isEndSession() {
return SmsDatabase.Types.isEndSessionType(type);
}
public boolean isNoRemoteSession() { return SmsDatabase.Types.isNoRemoteSessionType(type); }
public boolean isEndSession() { return SmsDatabase.Types.isEndSessionType(type); }
public boolean isLokiSessionRestoreSent() { return SmsDatabase.Types.isLokiSessionRestoreSentType(type); }

View file

@ -180,7 +180,7 @@ public abstract class MessageRecord extends DisplayRecord {
public boolean isUpdate() {
return isGroupAction() || isJoined() || isExpirationTimerUpdate() || isCallLog() ||
isEndSession() || isIdentityUpdate() || isIdentityVerified() || isIdentityDefault() || isNoRemoteSession() || isLokiSessionRestoreSent();
isEndSession() || isIdentityUpdate() || isIdentityVerified() || isIdentityDefault() || isLokiSessionRestoreSent();
}
public boolean isMediaPending() {

View file

@ -99,14 +99,10 @@ public class SmsMessageRecord extends MessageRecord {
return emphasisAdded(context.getString(R.string.ConversationItem_received_key_exchange_message_tap_to_process));
} else if (SmsDatabase.Types.isDuplicateMessageType(type)) {
return emphasisAdded(context.getString(R.string.SmsMessageRecord_duplicate_message));
} else if (SmsDatabase.Types.isNoRemoteSessionType(type)) {
return emphasisAdded(context.getString(R.string.MessageDisplayHelper_message_encrypted_for_non_existing_session));
} else if (isLokiSessionRestoreSent()) {
return emphasisAdded(context.getString(R.string.MessageRecord_session_restore_sent, recipient.toShortString()));
} else if (isNoRemoteSession()) {
if (recipient.isGroupRecipient()) {
return emphasisAdded(context.getString(R.string.MessageDisplayHelper_message_encrypted_for_non_existing_session));
} else {
return emphasisAdded(context.getString(R.string.MessageRecord_session_restore_required, recipient.toShortString()));
}
} else if (isEndSession() && isOutgoing()) {
return emphasisAdded(context.getString(R.string.SmsMessageRecord_secure_session_reset));
} else if (isEndSession()) {

View file

@ -80,14 +80,10 @@ public class ThreadRecord extends DisplayRecord {
return emphasisAdded(context.getString(R.string.ConversationListItem_key_exchange_message));
} else if (SmsDatabase.Types.isFailedDecryptType(type)) {
return emphasisAdded(context.getString(R.string.MessageDisplayHelper_bad_encrypted_message));
} else if (SmsDatabase.Types.isNoRemoteSessionType(type)) {
return emphasisAdded(context.getString(R.string.MessageDisplayHelper_message_encrypted_for_non_existing_session));
} else if (isLokiSessionRestoreSent()) {
return emphasisAdded(context.getString(R.string.MessageRecord_session_restore_sent, recipient.toShortString()));
} else if (isNoRemoteSession()) {
if (recipient.isGroupRecipient()) {
return emphasisAdded(context.getString(R.string.MessageDisplayHelper_message_encrypted_for_non_existing_session));
} else {
return emphasisAdded(context.getString(R.string.MessageRecord_session_restore_required, recipient.toShortString()));
}
} else if (SmsDatabase.Types.isEndSessionType(type)) {
return emphasisAdded(context.getString(R.string.ThreadRecord_secure_session_reset));
} else if (MmsSmsColumns.Types.isLegacyType(type)) {

View file

@ -42,6 +42,7 @@ import org.thoughtcrime.securesms.crypto.storage.SignalProtocolStoreImpl;
import org.thoughtcrime.securesms.crypto.storage.TextSecureSessionStore;
import org.thoughtcrime.securesms.database.Address;
import org.thoughtcrime.securesms.database.AttachmentDatabase;
import org.thoughtcrime.securesms.database.Database;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.GroupDatabase;
import org.thoughtcrime.securesms.database.GroupReceiptDatabase;
@ -74,7 +75,6 @@ import org.thoughtcrime.securesms.loki.LokiPreKeyBundleDatabase;
import org.thoughtcrime.securesms.loki.LokiPreKeyRecordDatabase;
import org.thoughtcrime.securesms.loki.LokiThreadDatabase;
import org.thoughtcrime.securesms.loki.MultiDeviceUtilities;
import org.thoughtcrime.securesms.loki.DebouncerCache;
import org.thoughtcrime.securesms.mms.IncomingMediaMessage;
import org.thoughtcrime.securesms.mms.MmsException;
import org.thoughtcrime.securesms.mms.OutgoingExpirationUpdateMessage;
@ -95,7 +95,6 @@ import org.thoughtcrime.securesms.sms.OutgoingEncryptedMessage;
import org.thoughtcrime.securesms.sms.OutgoingEndSessionMessage;
import org.thoughtcrime.securesms.sms.OutgoingTextMessage;
import org.thoughtcrime.securesms.stickers.StickerLocator;
import org.thoughtcrime.securesms.util.Debouncer;
import org.thoughtcrime.securesms.util.GroupUtil;
import org.thoughtcrime.securesms.util.Hex;
import org.thoughtcrime.securesms.util.IdentityUtil;
@ -276,9 +275,11 @@ 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)) {
@ -1394,51 +1395,38 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
if (insertResult.isPresent()) {
smsDatabase.markAsDecryptFailed(insertResult.get().getMessageId());
MessageNotifier.updateNotification(context, insertResult.get().getThreadId());
// MessageNotifier.updateNotification(context, insertResult.get().getThreadId());
}
} else {
smsDatabase.markAsDecryptFailed(smsMessageId.get());
}
triggerSessionRestorePrompt(sender);
}
private void handleNoSessionMessage(@NonNull String sender, int senderDevice, long timestamp,
@NonNull Optional<Long> smsMessageId)
{
Recipient recipient = Recipient.from(context, Address.fromSerialized(sender), false);
if (recipient.isGroupRecipient()) { return; }
SmsDatabase smsDatabase = DatabaseFactory.getSmsDatabase(context);
long threadID = DatabaseFactory.getThreadDatabase(context).getThreadIdIfExistsFor(recipient);
LokiThreadFriendRequestStatus friendRequestStatus = DatabaseFactory.getLokiThreadDatabase(context).getFriendRequestStatus(threadID);
/*
If we are friends with the user or we sent a friend request to them and we got a message back with no session then we want to try and restore the session automatically.
otherwise if we're not friends or our friend request expired then we need to prompt the user for action
*/
if (friendRequestStatus == LokiThreadFriendRequestStatus.FRIENDS || friendRequestStatus == LokiThreadFriendRequestStatus.REQUEST_SENT) {
autoRestoreSession(sender);
} else if (friendRequestStatus == LokiThreadFriendRequestStatus.NONE || friendRequestStatus == LokiThreadFriendRequestStatus.REQUEST_EXPIRED) {
SmsDatabase smsDatabase = DatabaseFactory.getSmsDatabase(context);
if (!smsMessageId.isPresent()) {
Optional<InsertResult> insertResult = insertPlaceholder(sender, senderDevice, timestamp);
if (!smsMessageId.isPresent()) {
if (!TextSecurePreferences.isShowingSessionRestorePrompt(context, sender)) {
Optional<InsertResult> insertResult = insertPlaceholder(sender, senderDevice, timestamp);
if (insertResult.isPresent()) {
smsDatabase.markAsNoSession(insertResult.get().getMessageId());
TextSecurePreferences.setShowingSessionRestorePrompt(context, sender, true);
//MessageNotifier.updateNotification(context, insertResult.get().getThreadId());
}
}
} else {
smsDatabase.markAsNoSession(smsMessageId.get());
if (insertResult.isPresent()) {
smsDatabase.markAsNoSession(insertResult.get().getMessageId());
// MessageNotifier.updateNotification(context, insertResult.get().getThreadId());
}
} else {
smsDatabase.markAsNoSession(smsMessageId.get());
}
triggerSessionRestorePrompt(sender);
}
private void autoRestoreSession(@NonNull String sender) {
// We don't want to keep spamming the user for an auto restore
String key = "restore_session_" + sender;
Debouncer debouncer = DebouncerCache.getDebouncer(key, 10000);
debouncer.publish(() -> MessageSender.sendRestoreSessionMessage(context, sender));
private void triggerSessionRestorePrompt(@NonNull String sender) {
Recipient primaryRecipient = getPrimaryDeviceRecipient(sender);
if (!primaryRecipient.isGroupRecipient()) {
long threadID = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(primaryRecipient);
DatabaseFactory.getLokiThreadDatabase(context).addSessionRestoreDevice(threadID, sender);
}
}
private void handleLegacyMessage(@NonNull String sender, int senderDevice, long timestamp,

View file

@ -1,7 +0,0 @@
package org.thoughtcrime.securesms.loki
import org.thoughtcrime.securesms.database.model.MessageRecord
interface ConversationUpdateItemViewDelegate {
fun updateItemButtonPressed(message: MessageRecord)
}

View file

@ -29,12 +29,7 @@ object FriendRequestHandler {
DatabaseFactory.getLokiThreadDatabase(context).setFriendRequestStatus(threadId, threadFriendStatus)
// If we sent a friend request then we need to hide the session restore prompt
if (type == ActionType.Sent) {
val smsDatabase = DatabaseFactory.getSmsDatabase(context)
smsDatabase.getMessages(threadId)
.filter { it.isNoRemoteSession && !it.isLokiSessionRestoreSent }
.forEach {
smsDatabase.markAsLokiSessionRestoreSent(it.id)
}
// TODO: Hide prompt
}
}

View file

@ -8,6 +8,7 @@ import org.thoughtcrime.securesms.database.Database
import org.thoughtcrime.securesms.database.DatabaseFactory
import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper
import org.thoughtcrime.securesms.recipients.Recipient
import org.thoughtcrime.securesms.util.TextSecurePreferences
import org.whispersystems.signalservice.internal.util.JsonUtil
import org.whispersystems.signalservice.loki.api.LokiPublicChat
import org.whispersystems.signalservice.loki.messaging.LokiThreadDatabaseProtocol
@ -140,4 +141,23 @@ class LokiThreadDatabase(context: Context, helper: SQLCipherOpenHelper) : Databa
override fun removePublicChat(threadID: Long) {
databaseHelper.writableDatabase.delete(publicChatTableName, "${Companion.threadID} = ?", arrayOf( threadID.toString() ))
}
// region Session Restore
fun addSessionRestoreDevice(threadID: Long, hexEncodedPublicKey: String) {
val devices = getSessionRestoreDevices(threadID).toMutableSet()
if (devices.add(hexEncodedPublicKey)) {
TextSecurePreferences.setStringPreference(context, "session_restore_devices_$threadID", devices.joinToString(","))
delegate?.handleSessionRestoreDevicesChanged(threadID)
}
}
fun getSessionRestoreDevices(threadID: Long): Set<String> {
return TextSecurePreferences.getStringPreference(context, "session_restore_devices_$threadID", "").split(",").toSet()
}
fun removeAllSessionRestoreDevices(threadID: Long) {
TextSecurePreferences.setStringPreference(context, "session_restore_devices_$threadID", "")
delegate?.handleSessionRestoreDevicesChanged(threadID)
}
// endregion
}

View file

@ -3,4 +3,5 @@ package org.thoughtcrime.securesms.loki
interface LokiThreadDatabaseDelegate {
fun handleThreadFriendRequestStatusChanged(threadID: Long)
fun handleSessionRestoreDevicesChanged(threadID: Long)
}

View file

@ -0,0 +1,55 @@
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
lateinit var recipient: Recipient
var onDismiss: (() -> Unit)? = null
var onRestore: (() -> Unit)? = null
constructor(context: Context) : this(context, null)
private constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0)
init {
LayoutInflater.from(context).inflate(R.layout.session_restore_banner, this, true)
restoreButton.setOnClickListener { onRestore?.invoke() }
dismissButton.setOnClickListener { onDismiss?.invoke() }
}
fun update(recipient: Recipient) {
this.recipient = recipient
restoreText.text = context.getString(R.string.session_restore_banner_message, recipient.toShortString())
}
fun show() {
container!!.visibility = View.VISIBLE;
}
fun hide() {
container!!.visibility = View.GONE
}
}

View file

@ -1228,14 +1228,6 @@ public class TextSecurePreferences {
public static long getRestorationTime(Context context) {
return getLongPreference(context, "restoration_time", 0);
}
public static void setShowingSessionRestorePrompt(Context context, String sender, boolean showingPrompt) {
setBooleanPreference(context, sender + "_showing_session_reset", showingPrompt);
}
public static boolean isShowingSessionRestorePrompt(Context context, String sender) {
return getBooleanPreference(context, sender + "_showing_session_reset", false);
}
// endregion
public static void clearAll(Context context) {