mirror of
https://github.com/oxen-io/session-android.git
synced 2025-01-11 16:33:39 +00:00
Move session restore prompt from message level to conversation level.
This commit is contained in:
parent
0caeb3a109
commit
97ffea040f
@ -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"
|
||||
|
@ -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>
|
||||
|
66
res/layout/session_restore_banner.xml
Normal file
66
res/layout/session_restore_banner.xml
Normal 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>
|
@ -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>
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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),
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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); }
|
||||
|
||||
|
@ -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() {
|
||||
|
@ -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()) {
|
||||
|
@ -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)) {
|
||||
|
@ -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,
|
||||
|
@ -1,7 +0,0 @@
|
||||
package org.thoughtcrime.securesms.loki
|
||||
|
||||
import org.thoughtcrime.securesms.database.model.MessageRecord
|
||||
|
||||
interface ConversationUpdateItemViewDelegate {
|
||||
fun updateItemButtonPressed(message: MessageRecord)
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
}
|
@ -3,4 +3,5 @@ package org.thoughtcrime.securesms.loki
|
||||
interface LokiThreadDatabaseDelegate {
|
||||
|
||||
fun handleThreadFriendRequestStatusChanged(threadID: Long)
|
||||
fun handleSessionRestoreDevicesChanged(threadID: Long)
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
@ -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) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user