mirror of
https://github.com/oxen-io/session-android.git
synced 2025-04-21 13:11:31 +00:00
Remove the concept of friend requests
This commit is contained in:
parent
21554441f3
commit
455471b20e
@ -44,23 +44,16 @@
|
|||||||
|
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:orientation="vertical"
|
|
||||||
android:layout_toStartOf="@+id/indicators_parent"
|
|
||||||
android:layout_alignWithParentIfMissing="true"
|
|
||||||
android:clipToPadding="false"
|
|
||||||
android:clipChildren="false">
|
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/body_bubble"
|
android:id="@+id/body_bubble"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginEnd="@dimen/massive_spacing"
|
android:layout_marginEnd="@dimen/massive_spacing"
|
||||||
android:layout_marginStart="12dp"
|
android:layout_marginStart="12dp"
|
||||||
android:paddingTop="@dimen/medium_spacing"
|
android:paddingTop="@dimen/medium_spacing"
|
||||||
android:paddingBottom="@dimen/medium_spacing"
|
android:paddingBottom="@dimen/medium_spacing"
|
||||||
|
android:layout_toStartOf="@+id/indicators_parent"
|
||||||
|
android:layout_alignWithParentIfMissing="true"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
android:clipToPadding="false"
|
android:clipToPadding="false"
|
||||||
android:clipChildren="false"
|
android:clipChildren="false"
|
||||||
@ -208,14 +201,6 @@
|
|||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<org.thoughtcrime.securesms.loki.views.FriendRequestView
|
|
||||||
android:id="@+id/friend_request_view"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:visibility="gone" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<org.thoughtcrime.securesms.components.AlertView
|
<org.thoughtcrime.securesms.components.AlertView
|
||||||
android:id="@+id/indicators_parent"
|
android:id="@+id/indicators_parent"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
|
@ -22,23 +22,16 @@
|
|||||||
android:clipToPadding="false"
|
android:clipToPadding="false"
|
||||||
android:clipChildren="false">
|
android:clipChildren="false">
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:orientation="vertical"
|
|
||||||
android:layout_toStartOf="@+id/indicators_parent"
|
|
||||||
android:layout_alignWithParentIfMissing="true"
|
|
||||||
android:clipToPadding="false"
|
|
||||||
android:clipChildren="false">
|
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/body_bubble"
|
android:id="@+id/body_bubble"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
android:layout_marginStart="@dimen/massive_spacing"
|
android:layout_marginStart="@dimen/massive_spacing"
|
||||||
android:paddingTop="@dimen/medium_spacing"
|
android:paddingTop="@dimen/medium_spacing"
|
||||||
android:paddingBottom="@dimen/medium_spacing"
|
android:paddingBottom="@dimen/medium_spacing"
|
||||||
|
android:layout_toStartOf="@+id/indicators_parent"
|
||||||
|
android:layout_alignWithParentIfMissing="true"
|
||||||
android:layout_gravity="end"
|
android:layout_gravity="end"
|
||||||
android:clipToPadding="false"
|
android:clipToPadding="false"
|
||||||
android:clipChildren="false"
|
android:clipChildren="false"
|
||||||
@ -161,14 +154,6 @@
|
|||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<org.thoughtcrime.securesms.loki.views.FriendRequestView
|
|
||||||
android:id="@+id/friend_request_view"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:visibility="gone" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<org.thoughtcrime.securesms.components.AlertView
|
<org.thoughtcrime.securesms.components.AlertView
|
||||||
android:id="@+id/indicators_parent"
|
android:id="@+id/indicators_parent"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
|
@ -1561,4 +1561,5 @@ Otrzymano wiadomość wymiany klucz dla niepoprawnej wersji protokołu.</string>
|
|||||||
<string name="fragment_contact_selection_contacts_title">Łączność</string>
|
<string name="fragment_contact_selection_contacts_title">Łączność</string>
|
||||||
<string name="fragment_contact_selection_closed_groups_title">Grupy zamknięte</string>
|
<string name="fragment_contact_selection_closed_groups_title">Grupy zamknięte</string>
|
||||||
<string name="fragment_contact_selection_open_groups_title">Otwórz grupy</string>
|
<string name="fragment_contact_selection_open_groups_title">Otwórz grupy</string>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -1358,6 +1358,7 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Session -->
|
||||||
<string name="continue_2">Продолжить</string>
|
<string name="continue_2">Продолжить</string>
|
||||||
<string name="copy">Копировать</string>
|
<string name="copy">Копировать</string>
|
||||||
<string name="invalid_url">Неверная ссылка</string>
|
<string name="invalid_url">Неверная ссылка</string>
|
||||||
|
@ -1655,7 +1655,6 @@
|
|||||||
|
|
||||||
|
|
||||||
<!-- Session -->
|
<!-- Session -->
|
||||||
|
|
||||||
<string name="continue_2">Continue</string>
|
<string name="continue_2">Continue</string>
|
||||||
<string name="copy">Copy</string>
|
<string name="copy">Copy</string>
|
||||||
<string name="invalid_url">Invalid URL</string>
|
<string name="invalid_url">Invalid URL</string>
|
||||||
|
@ -61,13 +61,13 @@ import org.thoughtcrime.securesms.logging.PersistentLogger;
|
|||||||
import org.thoughtcrime.securesms.logging.UncaughtExceptionLogger;
|
import org.thoughtcrime.securesms.logging.UncaughtExceptionLogger;
|
||||||
import org.thoughtcrime.securesms.loki.activities.HomeActivity;
|
import org.thoughtcrime.securesms.loki.activities.HomeActivity;
|
||||||
import org.thoughtcrime.securesms.loki.api.BackgroundPollWorker;
|
import org.thoughtcrime.securesms.loki.api.BackgroundPollWorker;
|
||||||
import org.thoughtcrime.securesms.loki.api.LokiPublicChatManager;
|
import org.thoughtcrime.securesms.loki.api.PublicChatManager;
|
||||||
import org.thoughtcrime.securesms.loki.api.LokiPushNotificationManager;
|
import org.thoughtcrime.securesms.loki.api.LokiPushNotificationManager;
|
||||||
import org.thoughtcrime.securesms.loki.database.LokiAPIDatabase;
|
import org.thoughtcrime.securesms.loki.database.LokiAPIDatabase;
|
||||||
import org.thoughtcrime.securesms.loki.database.LokiThreadDatabase;
|
import org.thoughtcrime.securesms.loki.database.LokiThreadDatabase;
|
||||||
import org.thoughtcrime.securesms.loki.database.LokiUserDatabase;
|
import org.thoughtcrime.securesms.loki.database.LokiUserDatabase;
|
||||||
import org.thoughtcrime.securesms.loki.protocol.EphemeralMessage;
|
import org.thoughtcrime.securesms.loki.protocol.EphemeralMessage;
|
||||||
import org.thoughtcrime.securesms.loki.protocol.LokiSessionResetImplementation;
|
import org.thoughtcrime.securesms.loki.protocol.SessionResetImplementation;
|
||||||
import org.thoughtcrime.securesms.loki.protocol.PushEphemeralMessageSendJob;
|
import org.thoughtcrime.securesms.loki.protocol.PushEphemeralMessageSendJob;
|
||||||
import org.thoughtcrime.securesms.loki.utilities.Broadcaster;
|
import org.thoughtcrime.securesms.loki.utilities.Broadcaster;
|
||||||
import org.thoughtcrime.securesms.notifications.DefaultMessageNotifier;
|
import org.thoughtcrime.securesms.notifications.DefaultMessageNotifier;
|
||||||
@ -154,7 +154,7 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc
|
|||||||
// Loki
|
// Loki
|
||||||
public MessageNotifier messageNotifier = null;
|
public MessageNotifier messageNotifier = null;
|
||||||
public Poller lokiPoller = null;
|
public Poller lokiPoller = null;
|
||||||
public LokiPublicChatManager lokiPublicChatManager = null;
|
public PublicChatManager publicChatManager = null;
|
||||||
private PublicChatAPI publicChatAPI = null;
|
private PublicChatAPI publicChatAPI = null;
|
||||||
public Broadcaster broadcaster = null;
|
public Broadcaster broadcaster = null;
|
||||||
public SignalCommunicationModule communicationModule;
|
public SignalCommunicationModule communicationModule;
|
||||||
@ -184,7 +184,7 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc
|
|||||||
LokiThreadDatabase threadDB = DatabaseFactory.getLokiThreadDatabase(this);
|
LokiThreadDatabase threadDB = DatabaseFactory.getLokiThreadDatabase(this);
|
||||||
LokiUserDatabase userDB = DatabaseFactory.getLokiUserDatabase(this);
|
LokiUserDatabase userDB = DatabaseFactory.getLokiUserDatabase(this);
|
||||||
String userPublicKey = TextSecurePreferences.getLocalNumber(this);
|
String userPublicKey = TextSecurePreferences.getLocalNumber(this);
|
||||||
LokiSessionResetImplementation sessionResetImpl = new LokiSessionResetImplementation(this);
|
SessionResetImplementation sessionResetImpl = new SessionResetImplementation(this);
|
||||||
if (userPublicKey != null) {
|
if (userPublicKey != null) {
|
||||||
SwarmAPI.Companion.configureIfNeeded(apiDB);
|
SwarmAPI.Companion.configureIfNeeded(apiDB);
|
||||||
SnodeAPI.Companion.configureIfNeeded(userPublicKey, apiDB, broadcaster);
|
SnodeAPI.Companion.configureIfNeeded(userPublicKey, apiDB, broadcaster);
|
||||||
@ -203,7 +203,7 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
resubmitProfilePictureIfNeeded();
|
resubmitProfilePictureIfNeeded();
|
||||||
lokiPublicChatManager = new LokiPublicChatManager(this);
|
publicChatManager = new PublicChatManager(this);
|
||||||
updateOpenGroupProfilePicturesIfNeeded();
|
updateOpenGroupProfilePicturesIfNeeded();
|
||||||
registerForFCMIfNeeded(false);
|
registerForFCMIfNeeded(false);
|
||||||
// ========
|
// ========
|
||||||
@ -229,8 +229,8 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc
|
|||||||
// Loki
|
// Loki
|
||||||
if (lokiPoller != null) { lokiPoller.setCaughtUp(false); }
|
if (lokiPoller != null) { lokiPoller.setCaughtUp(false); }
|
||||||
startPollingIfNeeded();
|
startPollingIfNeeded();
|
||||||
lokiPublicChatManager.markAllAsNotCaughtUp();
|
publicChatManager.markAllAsNotCaughtUp();
|
||||||
lokiPublicChatManager.startPollersIfNeeded();
|
publicChatManager.startPollersIfNeeded();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -241,7 +241,7 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc
|
|||||||
messageNotifier.setVisibleThread(-1);
|
messageNotifier.setVisibleThread(-1);
|
||||||
// Loki
|
// Loki
|
||||||
if (lokiPoller != null) { lokiPoller.stopIfNeeded(); }
|
if (lokiPoller != null) { lokiPoller.stopIfNeeded(); }
|
||||||
if (lokiPublicChatManager != null) { lokiPublicChatManager.stopPollers(); }
|
if (publicChatManager != null) { publicChatManager.stopPollers(); }
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -322,7 +322,7 @@ public class GroupCreateActivity extends PassphraseRequiredActionBarActivity
|
|||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
Intent intent = new Intent(GroupCreateActivity.this, PushContactSelectionActivity.class);
|
Intent intent = new Intent(GroupCreateActivity.this, PushContactSelectionActivity.class);
|
||||||
intent.putExtra(ContactSelectionListFragment.DISPLAY_MODE, DisplayMode.FLAG_FRIENDS);
|
intent.putExtra(ContactSelectionListFragment.DISPLAY_MODE, DisplayMode.FLAG_CONTACTS);
|
||||||
startActivityForResult(intent, PICK_CONTACT);
|
startActivityForResult(intent, PICK_CONTACT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -53,7 +53,7 @@ public class InviteActivity extends PassphraseRequiredActionBarActivity {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState, boolean ready) {
|
protected void onCreate(Bundle savedInstanceState, boolean ready) {
|
||||||
getIntent().putExtra(ContactSelectionListFragment.DISPLAY_MODE, DisplayMode.FLAG_FRIENDS);
|
getIntent().putExtra(ContactSelectionListFragment.DISPLAY_MODE, DisplayMode.FLAG_CONTACTS);
|
||||||
getIntent().putExtra(ContactSelectionListFragment.MULTI_SELECT, true);
|
getIntent().putExtra(ContactSelectionListFragment.MULTI_SELECT, true);
|
||||||
getIntent().putExtra(ContactSelectionListFragment.REFRESHABLE, false);
|
getIntent().putExtra(ContactSelectionListFragment.REFRESHABLE, false);
|
||||||
|
|
||||||
|
@ -84,7 +84,7 @@ public class TypingStatusSender {
|
|||||||
ThreadDatabase threadDatabase = DatabaseFactory.getThreadDatabase(context);
|
ThreadDatabase threadDatabase = DatabaseFactory.getThreadDatabase(context);
|
||||||
Recipient recipient = threadDatabase.getRecipientForThreadId(threadId);
|
Recipient recipient = threadDatabase.getRecipientForThreadId(threadId);
|
||||||
// Loki - Check whether we want to send a typing indicator to this user
|
// Loki - Check whether we want to send a typing indicator to this user
|
||||||
if (!SessionMetaProtocol.shouldSendTypingIndicator(recipient, context)) { return; }
|
if (recipient != null && !SessionMetaProtocol.shouldSendTypingIndicator(recipient.getAddress())) { return; }
|
||||||
// Loki - Take into account multi device
|
// Loki - Take into account multi device
|
||||||
Set<String> linkedDevices = MultiDeviceProtocol.shared.getAllLinkedDevices(recipient.getAddress().serialize());
|
Set<String> linkedDevices = MultiDeviceProtocol.shared.getAllLinkedDevices(recipient.getAddress().serialize());
|
||||||
for (String device : linkedDevices) {
|
for (String device : linkedDevices) {
|
||||||
|
@ -68,7 +68,6 @@ import android.view.View.OnFocusChangeListener;
|
|||||||
import android.view.View.OnKeyListener;
|
import android.view.View.OnKeyListener;
|
||||||
import android.view.WindowManager;
|
import android.view.WindowManager;
|
||||||
import android.view.inputmethod.EditorInfo;
|
import android.view.inputmethod.EditorInfo;
|
||||||
import android.view.inputmethod.InputMethodManager;
|
|
||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
import android.widget.ImageButton;
|
import android.widget.ImageButton;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
@ -81,7 +80,6 @@ import com.annimon.stream.Stream;
|
|||||||
import org.greenrobot.eventbus.EventBus;
|
import org.greenrobot.eventbus.EventBus;
|
||||||
import org.greenrobot.eventbus.Subscribe;
|
import org.greenrobot.eventbus.Subscribe;
|
||||||
import org.greenrobot.eventbus.ThreadMode;
|
import org.greenrobot.eventbus.ThreadMode;
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
import org.thoughtcrime.securesms.ApplicationContext;
|
import org.thoughtcrime.securesms.ApplicationContext;
|
||||||
import org.thoughtcrime.securesms.ExpirationDialog;
|
import org.thoughtcrime.securesms.ExpirationDialog;
|
||||||
import org.thoughtcrime.securesms.GroupCreateActivity;
|
import org.thoughtcrime.securesms.GroupCreateActivity;
|
||||||
@ -159,10 +157,8 @@ import org.thoughtcrime.securesms.loki.database.LokiThreadDatabase;
|
|||||||
import org.thoughtcrime.securesms.loki.database.LokiThreadDatabaseDelegate;
|
import org.thoughtcrime.securesms.loki.database.LokiThreadDatabaseDelegate;
|
||||||
import org.thoughtcrime.securesms.loki.database.LokiUserDatabase;
|
import org.thoughtcrime.securesms.loki.database.LokiUserDatabase;
|
||||||
import org.thoughtcrime.securesms.loki.protocol.ClosedGroupsProtocol;
|
import org.thoughtcrime.securesms.loki.protocol.ClosedGroupsProtocol;
|
||||||
import org.thoughtcrime.securesms.loki.protocol.FriendRequestProtocol;
|
|
||||||
import org.thoughtcrime.securesms.loki.protocol.SessionManagementProtocol;
|
import org.thoughtcrime.securesms.loki.protocol.SessionManagementProtocol;
|
||||||
import org.thoughtcrime.securesms.loki.utilities.MentionManagerUtilities;
|
import org.thoughtcrime.securesms.loki.utilities.MentionManagerUtilities;
|
||||||
import org.thoughtcrime.securesms.loki.views.FriendRequestViewDelegate;
|
|
||||||
import org.thoughtcrime.securesms.loki.views.MentionCandidateSelectionView;
|
import org.thoughtcrime.securesms.loki.views.MentionCandidateSelectionView;
|
||||||
import org.thoughtcrime.securesms.loki.views.SessionRestoreBannerView;
|
import org.thoughtcrime.securesms.loki.views.SessionRestoreBannerView;
|
||||||
import org.thoughtcrime.securesms.mediasend.Media;
|
import org.thoughtcrime.securesms.mediasend.Media;
|
||||||
@ -231,7 +227,6 @@ import org.whispersystems.signalservice.loki.protocol.mentions.Mention;
|
|||||||
import org.whispersystems.signalservice.loki.protocol.mentions.MentionsManager;
|
import org.whispersystems.signalservice.loki.protocol.mentions.MentionsManager;
|
||||||
import org.whispersystems.signalservice.loki.protocol.meta.SessionMetaProtocol;
|
import org.whispersystems.signalservice.loki.protocol.meta.SessionMetaProtocol;
|
||||||
import org.whispersystems.signalservice.loki.protocol.multidevice.MultiDeviceProtocol;
|
import org.whispersystems.signalservice.loki.protocol.multidevice.MultiDeviceProtocol;
|
||||||
import org.whispersystems.signalservice.loki.protocol.todo.LokiThreadFriendRequestStatus;
|
|
||||||
import org.whispersystems.signalservice.loki.utilities.PublicKeyValidation;
|
import org.whispersystems.signalservice.loki.utilities.PublicKeyValidation;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@ -272,8 +267,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||||||
ComposeText.CursorPositionChangedListener,
|
ComposeText.CursorPositionChangedListener,
|
||||||
ConversationSearchBottomBar.EventListener,
|
ConversationSearchBottomBar.EventListener,
|
||||||
StickerKeyboardProvider.StickerEventListener,
|
StickerKeyboardProvider.StickerEventListener,
|
||||||
LokiThreadDatabaseDelegate,
|
LokiThreadDatabaseDelegate
|
||||||
FriendRequestViewDelegate
|
|
||||||
{
|
{
|
||||||
private static final String TAG = ConversationActivity.class.getSimpleName();
|
private static final String TAG = ConversationActivity.class.getSimpleName();
|
||||||
|
|
||||||
@ -386,7 +380,6 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||||||
getWindow().getDecorView().setBackgroundColor(color);
|
getWindow().getDecorView().setBackgroundColor(color);
|
||||||
|
|
||||||
fragment = initFragment(R.id.fragment_content, new ConversationFragment(), dynamicLanguage.getCurrentLocale());
|
fragment = initFragment(R.id.fragment_content, new ConversationFragment(), dynamicLanguage.getCurrentLocale());
|
||||||
fragment.friendRequestViewDelegate = this;
|
|
||||||
|
|
||||||
registerMessageStatusObserver("calculatingPoW");
|
registerMessageStatusObserver("calculatingPoW");
|
||||||
registerMessageStatusObserver("contactingNetwork");
|
registerMessageStatusObserver("contactingNetwork");
|
||||||
@ -554,8 +547,6 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||||||
|
|
||||||
DatabaseFactory.getLokiThreadDatabase(this).setDelegate(this);
|
DatabaseFactory.getLokiThreadDatabase(this).setDelegate(this);
|
||||||
|
|
||||||
updateInputPanel();
|
|
||||||
|
|
||||||
updateSessionRestoreBanner();
|
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)));
|
||||||
@ -2252,26 +2243,6 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||||||
updateLinkPreviewState();
|
updateLinkPreviewState();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void handleThreadFriendRequestStatusChanged(long threadID) {
|
|
||||||
if (recipient.isGroupRecipient()) { return; }
|
|
||||||
boolean isUpdateNeeded = false;
|
|
||||||
if (threadID == this.threadId) {
|
|
||||||
isUpdateNeeded = true;
|
|
||||||
} else {
|
|
||||||
String thisThreadPublicKey = recipient.getAddress().serialize();
|
|
||||||
Set<String> thisThreadAssociatedDevices = MultiDeviceProtocol.shared.getAllLinkedDevices(thisThreadPublicKey);
|
|
||||||
Recipient changedThreadRecipient = DatabaseFactory.getThreadDatabase(this).getRecipientForThreadId(threadID);
|
|
||||||
String changedThreadPublicKey = changedThreadRecipient.getAddress().serialize();
|
|
||||||
for (String device : thisThreadAssociatedDevices) {
|
|
||||||
if (device.equals(changedThreadPublicKey)) { isUpdateNeeded = true; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (isUpdateNeeded) {
|
|
||||||
updateInputPanel();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handleSessionRestoreDevicesChanged(long threadID) {
|
public void handleSessionRestoreDevicesChanged(long threadID) {
|
||||||
if (threadID == this.threadId) {
|
if (threadID == this.threadId) {
|
||||||
@ -2279,21 +2250,6 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateInputPanel() {
|
|
||||||
boolean shouldInputPanelBeEnabled = FriendRequestProtocol.shouldInputPanelBeEnabled(this, recipient);
|
|
||||||
Util.runOnMain(() -> {
|
|
||||||
updateToggleButtonState();
|
|
||||||
String hint = shouldInputPanelBeEnabled ? "Message" : "Pending session request";
|
|
||||||
inputPanel.setHint(hint);
|
|
||||||
inputPanel.setEnabled(shouldInputPanelBeEnabled);
|
|
||||||
if (shouldInputPanelBeEnabled && inputPanel.getVisibility() == View.VISIBLE) {
|
|
||||||
inputPanel.composeText.requestFocus();
|
|
||||||
InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);
|
|
||||||
inputMethodManager.showSoftInput(inputPanel.composeText, 0);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void sendMessage() {
|
private void sendMessage() {
|
||||||
if (inputPanel.isRecordingInLockedMode()) {
|
if (inputPanel.isRecordingInLockedMode()) {
|
||||||
inputPanel.releaseRecordingLock();
|
inputPanel.releaseRecordingLock();
|
||||||
@ -2395,11 +2351,6 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||||||
outgoingMessage = outgoingMessageCandidate;
|
outgoingMessage = outgoingMessageCandidate;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Loki - Send a friend request if we're not yet friends with the user in question
|
|
||||||
LokiThreadFriendRequestStatus friendRequestStatus = DatabaseFactory.getLokiThreadDatabase(context).getFriendRequestStatus(threadId);
|
|
||||||
outgoingMessage.isFriendRequest = !isGroupConversation() && friendRequestStatus != LokiThreadFriendRequestStatus.FRIENDS
|
|
||||||
&& !SessionMetaProtocol.shared.isNoteToSelf(recipient.getAddress().serialize()); // Needed for stageOutgoingMessage(...)
|
|
||||||
|
|
||||||
if (clearComposeBox) {
|
if (clearComposeBox) {
|
||||||
inputPanel.clearQuote();
|
inputPanel.clearQuote();
|
||||||
attachmentManager.clear(glideRequests, false);
|
attachmentManager.clear(glideRequests, false);
|
||||||
@ -2448,11 +2399,6 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||||||
message = new OutgoingTextMessage(recipient, messageBody, expiresIn, subscriptionId);
|
message = new OutgoingTextMessage(recipient, messageBody, expiresIn, subscriptionId);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Loki - Send a friend request if we're not yet friends with the user in question
|
|
||||||
LokiThreadFriendRequestStatus friendRequestStatus = DatabaseFactory.getLokiThreadDatabase(context).getFriendRequestStatus(threadId);
|
|
||||||
message.isFriendRequest = !isGroupConversation() && friendRequestStatus != LokiThreadFriendRequestStatus.FRIENDS
|
|
||||||
&& !SessionMetaProtocol.shared.isNoteToSelf(recipient.getAddress().serialize()); // Needed for stageOutgoingMessage(...)
|
|
||||||
|
|
||||||
silentlySetComposeText("");
|
silentlySetComposeText("");
|
||||||
final long id = fragment.stageOutgoingMessage(message);
|
final long id = fragment.stageOutgoingMessage(message);
|
||||||
|
|
||||||
@ -2482,13 +2428,6 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void updateToggleButtonState() {
|
private void updateToggleButtonState() {
|
||||||
if (!FriendRequestProtocol.shouldAttachmentButtonBeEnabled(this, recipient)) {
|
|
||||||
buttonToggle.display(sendButton);
|
|
||||||
quickAttachmentToggle.hide();
|
|
||||||
inlineAttachmentToggle.hide();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (inputPanel.isRecordingInLockedMode()) {
|
if (inputPanel.isRecordingInLockedMode()) {
|
||||||
buttonToggle.display(sendButton);
|
buttonToggle.display(sendButton);
|
||||||
quickAttachmentToggle.show();
|
quickAttachmentToggle.show();
|
||||||
@ -3192,19 +3131,5 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||||||
updateSubtitleTextView();
|
updateSubtitleTextView();
|
||||||
updateMessageStatusProgressBar();
|
updateMessageStatusProgressBar();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void acceptFriendRequest(@NotNull MessageRecord friendRequest) {
|
|
||||||
if (recipient.isGroupRecipient()) { return; }
|
|
||||||
FriendRequestProtocol.acceptFriendRequest(this, recipient);
|
|
||||||
updateInputPanel();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void rejectFriendRequest(@NotNull MessageRecord friendRequest) {
|
|
||||||
if (recipient.isGroupRecipient()) { return; }
|
|
||||||
FriendRequestProtocol.rejectFriendRequest(this, recipient);
|
|
||||||
updateInputPanel();
|
|
||||||
}
|
|
||||||
// endregion
|
// endregion
|
||||||
}
|
}
|
||||||
|
@ -40,7 +40,6 @@ import org.thoughtcrime.securesms.database.MmsSmsDatabase;
|
|||||||
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.logging.Log;
|
import org.thoughtcrime.securesms.logging.Log;
|
||||||
import org.thoughtcrime.securesms.loki.views.FriendRequestViewDelegate;
|
|
||||||
import org.thoughtcrime.securesms.mms.GlideRequests;
|
import org.thoughtcrime.securesms.mms.GlideRequests;
|
||||||
import org.thoughtcrime.securesms.mms.SlideDeck;
|
import org.thoughtcrime.securesms.mms.SlideDeck;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||||
@ -108,8 +107,6 @@ public class ConversationAdapter <V extends View & BindableConversationItem>
|
|||||||
private MessageRecord recordToPulseHighlight;
|
private MessageRecord recordToPulseHighlight;
|
||||||
private String searchQuery;
|
private String searchQuery;
|
||||||
|
|
||||||
public FriendRequestViewDelegate friendRequestViewDelegate; // Loki
|
|
||||||
|
|
||||||
protected static class ViewHolder extends RecyclerView.ViewHolder {
|
protected static class ViewHolder extends RecyclerView.ViewHolder {
|
||||||
public <V extends View & BindableConversationItem> ViewHolder(final @NonNull V itemView) {
|
public <V extends View & BindableConversationItem> ViewHolder(final @NonNull V itemView) {
|
||||||
super(itemView);
|
super(itemView);
|
||||||
@ -202,11 +199,7 @@ public class ConversationAdapter <V extends View & BindableConversationItem>
|
|||||||
MessageRecord previousRecord = adapterPosition < getItemCount() - 1 && !isFooterPosition(adapterPosition + 1) ? getRecordForPositionOrThrow(adapterPosition + 1) : null;
|
MessageRecord previousRecord = adapterPosition < getItemCount() - 1 && !isFooterPosition(adapterPosition + 1) ? getRecordForPositionOrThrow(adapterPosition + 1) : null;
|
||||||
MessageRecord nextRecord = adapterPosition > 0 && !isHeaderPosition(adapterPosition - 1) ? getRecordForPositionOrThrow(adapterPosition - 1) : null;
|
MessageRecord nextRecord = adapterPosition > 0 && !isHeaderPosition(adapterPosition - 1) ? getRecordForPositionOrThrow(adapterPosition - 1) : null;
|
||||||
|
|
||||||
BindableConversationItem conversationItem = viewHolder.getView();
|
viewHolder.getView().bind(messageRecord,
|
||||||
if (conversationItem instanceof ConversationItem) {
|
|
||||||
((ConversationItem)conversationItem).friendRequestViewDelegate = this.friendRequestViewDelegate;
|
|
||||||
}
|
|
||||||
conversationItem.bind(messageRecord,
|
|
||||||
Optional.fromNullable(previousRecord),
|
Optional.fromNullable(previousRecord),
|
||||||
Optional.fromNullable(nextRecord),
|
Optional.fromNullable(nextRecord),
|
||||||
glideRequests,
|
glideRequests,
|
||||||
|
@ -79,7 +79,6 @@ 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.linkpreview.LinkPreview;
|
import org.thoughtcrime.securesms.linkpreview.LinkPreview;
|
||||||
import org.thoughtcrime.securesms.logging.Log;
|
import org.thoughtcrime.securesms.logging.Log;
|
||||||
import org.thoughtcrime.securesms.loki.views.FriendRequestViewDelegate;
|
|
||||||
import org.thoughtcrime.securesms.longmessage.LongMessageActivity;
|
import org.thoughtcrime.securesms.longmessage.LongMessageActivity;
|
||||||
import org.thoughtcrime.securesms.mediasend.Media;
|
import org.thoughtcrime.securesms.mediasend.Media;
|
||||||
import org.thoughtcrime.securesms.mms.GlideApp;
|
import org.thoughtcrime.securesms.mms.GlideApp;
|
||||||
@ -151,7 +150,6 @@ public class ConversationFragment extends Fragment
|
|||||||
private View composeDivider;
|
private View composeDivider;
|
||||||
private View scrollToBottomButton;
|
private View scrollToBottomButton;
|
||||||
private TextView scrollDateHeader;
|
private TextView scrollDateHeader;
|
||||||
public FriendRequestViewDelegate friendRequestViewDelegate; // Loki
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle icicle) {
|
public void onCreate(Bundle icicle) {
|
||||||
@ -706,7 +704,6 @@ public class ConversationFragment extends Fragment
|
|||||||
if (adapter == null) {
|
if (adapter == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
adapter.friendRequestViewDelegate = this.friendRequestViewDelegate;
|
|
||||||
|
|
||||||
if (cursor.getCount() >= PARTIAL_CONVERSATION_LIMIT && loader.hasLimit()) {
|
if (cursor.getCount() >= PARTIAL_CONVERSATION_LIMIT && loader.hasLimit()) {
|
||||||
adapter.setFooterView(topLoadMoreView);
|
adapter.setFooterView(topLoadMoreView);
|
||||||
|
@ -86,10 +86,7 @@ import org.thoughtcrime.securesms.jobs.SmsSendJob;
|
|||||||
import org.thoughtcrime.securesms.linkpreview.LinkPreview;
|
import org.thoughtcrime.securesms.linkpreview.LinkPreview;
|
||||||
import org.thoughtcrime.securesms.linkpreview.LinkPreviewUtil;
|
import org.thoughtcrime.securesms.linkpreview.LinkPreviewUtil;
|
||||||
import org.thoughtcrime.securesms.logging.Log;
|
import org.thoughtcrime.securesms.logging.Log;
|
||||||
import org.thoughtcrime.securesms.loki.database.LokiMessageDatabase;
|
|
||||||
import org.thoughtcrime.securesms.loki.utilities.MentionUtilities;
|
import org.thoughtcrime.securesms.loki.utilities.MentionUtilities;
|
||||||
import org.thoughtcrime.securesms.loki.views.FriendRequestView;
|
|
||||||
import org.thoughtcrime.securesms.loki.views.FriendRequestViewDelegate;
|
|
||||||
import org.thoughtcrime.securesms.loki.views.ProfilePictureView;
|
import org.thoughtcrime.securesms.loki.views.ProfilePictureView;
|
||||||
import org.thoughtcrime.securesms.mms.GlideRequests;
|
import org.thoughtcrime.securesms.mms.GlideRequests;
|
||||||
import org.thoughtcrime.securesms.mms.ImageSlide;
|
import org.thoughtcrime.securesms.mms.ImageSlide;
|
||||||
@ -158,7 +155,6 @@ public class ConversationItem extends LinearLayout
|
|||||||
private ViewGroup contactPhotoHolder;
|
private ViewGroup contactPhotoHolder;
|
||||||
private AlertView alertView;
|
private AlertView alertView;
|
||||||
private ViewGroup container;
|
private ViewGroup container;
|
||||||
private FriendRequestView friendRequestView;
|
|
||||||
|
|
||||||
private @NonNull Set<MessageRecord> batchSelected = new HashSet<>();
|
private @NonNull Set<MessageRecord> batchSelected = new HashSet<>();
|
||||||
private Recipient conversationRecipient;
|
private Recipient conversationRecipient;
|
||||||
@ -182,8 +178,6 @@ public class ConversationItem extends LinearLayout
|
|||||||
|
|
||||||
private final Context context;
|
private final Context context;
|
||||||
|
|
||||||
public FriendRequestViewDelegate friendRequestViewDelegate; // Loki
|
|
||||||
|
|
||||||
public ConversationItem(Context context) {
|
public ConversationItem(Context context) {
|
||||||
this(context, null);
|
this(context, null);
|
||||||
}
|
}
|
||||||
@ -223,7 +217,6 @@ public class ConversationItem extends LinearLayout
|
|||||||
this.groupSenderHolder = findViewById(R.id.group_sender_holder);
|
this.groupSenderHolder = findViewById(R.id.group_sender_holder);
|
||||||
this.quoteView = findViewById(R.id.quote_view);
|
this.quoteView = findViewById(R.id.quote_view);
|
||||||
this.container = findViewById(R.id.container);
|
this.container = findViewById(R.id.container);
|
||||||
this.friendRequestView = findViewById(R.id.friend_request_view);
|
|
||||||
|
|
||||||
setOnClickListener(new ClickListener(null));
|
setOnClickListener(new ClickListener(null));
|
||||||
|
|
||||||
@ -269,7 +262,6 @@ public class ConversationItem extends LinearLayout
|
|||||||
setQuote(messageRecord, previousMessageRecord, nextMessageRecord, groupThread);
|
setQuote(messageRecord, previousMessageRecord, nextMessageRecord, groupThread);
|
||||||
setMessageSpacing(context, messageRecord, previousMessageRecord, nextMessageRecord, groupThread);
|
setMessageSpacing(context, messageRecord, previousMessageRecord, nextMessageRecord, groupThread);
|
||||||
setFooter(messageRecord, nextMessageRecord, locale, groupThread);
|
setFooter(messageRecord, nextMessageRecord, locale, groupThread);
|
||||||
setFriendRequestView(messageRecord);
|
|
||||||
adjustMarginsIfNeeded(messageRecord);
|
adjustMarginsIfNeeded(messageRecord);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -807,8 +799,8 @@ public class ConversationItem extends LinearLayout
|
|||||||
layoutParams.setMarginStart((groupThread && !isRSSFeed) ? groupThreadMargin : defaultMargin);
|
layoutParams.setMarginStart((groupThread && !isRSSFeed) ? groupThreadMargin : defaultMargin);
|
||||||
bodyBubble.setLayoutParams(layoutParams);
|
bodyBubble.setLayoutParams(layoutParams);
|
||||||
if (profilePictureView == null) return;
|
if (profilePictureView == null) return;
|
||||||
profilePictureView.setHexEncodedPublicKey(recipient.getAddress().toString());
|
profilePictureView.setPublicKey(recipient.getAddress().toString());
|
||||||
profilePictureView.setAdditionalHexEncodedPublicKey(null);
|
profilePictureView.setAdditionalPublicKey(null);
|
||||||
profilePictureView.setRSSFeed(false);
|
profilePictureView.setRSSFeed(false);
|
||||||
profilePictureView.setGlide(glideRequests);
|
profilePictureView.setGlide(glideRequests);
|
||||||
profilePictureView.update();
|
profilePictureView.update();
|
||||||
@ -920,11 +912,6 @@ public class ConversationItem extends LinearLayout
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setFriendRequestView(@NonNull MessageRecord record) {
|
|
||||||
friendRequestView.setDelegate(friendRequestViewDelegate);
|
|
||||||
friendRequestView.update(record);
|
|
||||||
}
|
|
||||||
|
|
||||||
private ConversationItemFooter getActiveFooter(@NonNull MessageRecord messageRecord) {
|
private ConversationItemFooter getActiveFooter(@NonNull MessageRecord messageRecord) {
|
||||||
if (hasSticker(messageRecord)) {
|
if (hasSticker(messageRecord)) {
|
||||||
return stickerFooter;
|
return stickerFooter;
|
||||||
@ -1067,10 +1054,8 @@ public class ConversationItem extends LinearLayout
|
|||||||
int spacingBottom = spacingTop;
|
int spacingBottom = spacingTop;
|
||||||
|
|
||||||
boolean isOutgoingStack = current.isOutgoing() && previous.orNull() != null && previous.get().isOutgoing();
|
boolean isOutgoingStack = current.isOutgoing() && previous.orNull() != null && previous.get().isOutgoing();
|
||||||
LokiMessageDatabase lokiMessageDatabase = DatabaseFactory.getLokiMessageDatabase(context);
|
|
||||||
boolean isPreviousMessageFriendRequest = previous.orNull() != null && lokiMessageDatabase.isFriendRequest(previous.get().id);
|
|
||||||
|
|
||||||
if (isOutgoingStack && isPreviousMessageFriendRequest) {
|
if (isOutgoingStack) {
|
||||||
spacingTop = readDimen(context, R.dimen.conversation_vertical_message_spacing_default);
|
spacingTop = readDimen(context, R.dimen.conversation_vertical_message_spacing_default);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -885,7 +885,7 @@ public class SmsDatabase extends MessagingDatabase {
|
|||||||
0, message.isSecureMessage() ? MmsSmsColumns.Types.getOutgoingEncryptedMessageType() : MmsSmsColumns.Types.getOutgoingSmsMessageType(),
|
0, message.isSecureMessage() ? MmsSmsColumns.Types.getOutgoingEncryptedMessageType() : MmsSmsColumns.Types.getOutgoingSmsMessageType(),
|
||||||
threadId, 0, new LinkedList<IdentityKeyMismatch>(),
|
threadId, 0, new LinkedList<IdentityKeyMismatch>(),
|
||||||
message.getSubscriptionId(), message.getExpiresIn(),
|
message.getSubscriptionId(), message.getExpiresIn(),
|
||||||
System.currentTimeMillis(), 0, false, message.isFriendRequest);
|
System.currentTimeMillis(), 0, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -934,15 +934,12 @@ public class SmsDatabase extends MessagingDatabase {
|
|||||||
List<IdentityKeyMismatch> mismatches = getMismatches(mismatchDocument);
|
List<IdentityKeyMismatch> mismatches = getMismatches(mismatchDocument);
|
||||||
Recipient recipient = Recipient.from(context, address, true);
|
Recipient recipient = Recipient.from(context, address, true);
|
||||||
|
|
||||||
// Loki - Check to see if this message was a friend request
|
|
||||||
boolean isFriendRequest = DatabaseFactory.getLokiMessageDatabase(context).isFriendRequest(messageId);
|
|
||||||
|
|
||||||
return new SmsMessageRecord(messageId, body, recipient,
|
return new SmsMessageRecord(messageId, body, recipient,
|
||||||
recipient,
|
recipient,
|
||||||
addressDeviceId,
|
addressDeviceId,
|
||||||
dateSent, dateReceived, deliveryReceiptCount, type,
|
dateSent, dateReceived, deliveryReceiptCount, type,
|
||||||
threadId, status, mismatches, subscriptionId,
|
threadId, status, mismatches, subscriptionId,
|
||||||
expiresIn, expireStarted, readReceiptCount, unidentified, isFriendRequest);
|
expiresIn, expireStarted, readReceiptCount, unidentified);
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<IdentityKeyMismatch> getMismatches(String document) {
|
private List<IdentityKeyMismatch> getMismatches(String document) {
|
||||||
|
@ -145,10 +145,9 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper {
|
|||||||
db.execSQL(LokiAPIDatabase.getCreateSessionRequestTimestampCacheCommand());
|
db.execSQL(LokiAPIDatabase.getCreateSessionRequestTimestampCacheCommand());
|
||||||
db.execSQL(LokiPreKeyBundleDatabase.getCreateTableCommand());
|
db.execSQL(LokiPreKeyBundleDatabase.getCreateTableCommand());
|
||||||
db.execSQL(LokiPreKeyRecordDatabase.getCreateTableCommand());
|
db.execSQL(LokiPreKeyRecordDatabase.getCreateTableCommand());
|
||||||
db.execSQL(LokiMessageDatabase.getCreateMessageFriendRequestTableCommand());
|
db.execSQL(LokiMessageDatabase.getCreateMessageIDTableCommand());
|
||||||
db.execSQL(LokiMessageDatabase.getCreateMessageToThreadMappingTableCommand());
|
db.execSQL(LokiMessageDatabase.getCreateMessageToThreadMappingTableCommand());
|
||||||
db.execSQL(LokiMessageDatabase.getCreateErrorMessageTableCommand());
|
db.execSQL(LokiMessageDatabase.getCreateErrorMessageTableCommand());
|
||||||
db.execSQL(LokiThreadDatabase.getCreateFriendRequestTableCommand());
|
|
||||||
db.execSQL(LokiThreadDatabase.getCreateSessionResetTableCommand());
|
db.execSQL(LokiThreadDatabase.getCreateSessionResetTableCommand());
|
||||||
db.execSQL(LokiThreadDatabase.getCreatePublicChatTableCommand());
|
db.execSQL(LokiThreadDatabase.getCreatePublicChatTableCommand());
|
||||||
db.execSQL(LokiUserDatabase.getCreateDisplayNameTableCommand());
|
db.execSQL(LokiUserDatabase.getCreateDisplayNameTableCommand());
|
||||||
|
@ -39,9 +39,6 @@ import network.loki.messenger.R;
|
|||||||
*/
|
*/
|
||||||
public class SmsMessageRecord extends MessageRecord {
|
public class SmsMessageRecord extends MessageRecord {
|
||||||
|
|
||||||
// Loki
|
|
||||||
private final boolean isFriendRequest;
|
|
||||||
|
|
||||||
public SmsMessageRecord(long id,
|
public SmsMessageRecord(long id,
|
||||||
String body, Recipient recipient,
|
String body, Recipient recipient,
|
||||||
Recipient individualRecipient,
|
Recipient individualRecipient,
|
||||||
@ -52,35 +49,17 @@ public class SmsMessageRecord extends MessageRecord {
|
|||||||
int status, List<IdentityKeyMismatch> mismatches,
|
int status, List<IdentityKeyMismatch> mismatches,
|
||||||
int subscriptionId, long expiresIn, long expireStarted,
|
int subscriptionId, long expiresIn, long expireStarted,
|
||||||
int readReceiptCount, boolean unidentified)
|
int readReceiptCount, boolean unidentified)
|
||||||
{
|
|
||||||
this(id, body, recipient, individualRecipient, recipientDeviceId, dateSent, dateReceived, deliveryReceiptCount, type, threadId, status, mismatches, subscriptionId, expiresIn, expireStarted, readReceiptCount, unidentified, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public SmsMessageRecord(long id,
|
|
||||||
String body, Recipient recipient,
|
|
||||||
Recipient individualRecipient,
|
|
||||||
int recipientDeviceId,
|
|
||||||
long dateSent, long dateReceived,
|
|
||||||
int deliveryReceiptCount,
|
|
||||||
long type, long threadId,
|
|
||||||
int status, List<IdentityKeyMismatch> mismatches,
|
|
||||||
int subscriptionId, long expiresIn, long expireStarted,
|
|
||||||
int readReceiptCount, boolean unidentified, boolean isFriendRequest)
|
|
||||||
{
|
{
|
||||||
super(id, body, recipient, individualRecipient, recipientDeviceId,
|
super(id, body, recipient, individualRecipient, recipientDeviceId,
|
||||||
dateSent, dateReceived, threadId, status, deliveryReceiptCount, type,
|
dateSent, dateReceived, threadId, status, deliveryReceiptCount, type,
|
||||||
mismatches, new LinkedList<>(), subscriptionId,
|
mismatches, new LinkedList<>(), subscriptionId,
|
||||||
expiresIn, expireStarted, readReceiptCount, unidentified);
|
expiresIn, expireStarted, readReceiptCount, unidentified);
|
||||||
this.isFriendRequest = isFriendRequest;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getType() {
|
public long getType() {
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Loki
|
|
||||||
public boolean isFriendRequest() { return isFriendRequest; }
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SpannableString getDisplayBody(@NonNull Context context) {
|
public SpannableString getDisplayBody(@NonNull Context context) {
|
||||||
Recipient recipient = getRecipient();
|
Recipient recipient = getRecipient();
|
||||||
|
@ -45,7 +45,7 @@ import org.thoughtcrime.securesms.jobs.StickerPackDownloadJob;
|
|||||||
import org.thoughtcrime.securesms.jobs.TypingSendJob;
|
import org.thoughtcrime.securesms.jobs.TypingSendJob;
|
||||||
import org.thoughtcrime.securesms.linkpreview.LinkPreviewRepository;
|
import org.thoughtcrime.securesms.linkpreview.LinkPreviewRepository;
|
||||||
import org.thoughtcrime.securesms.logging.Log;
|
import org.thoughtcrime.securesms.logging.Log;
|
||||||
import org.thoughtcrime.securesms.loki.protocol.LokiSessionResetImplementation;
|
import org.thoughtcrime.securesms.loki.protocol.SessionResetImplementation;
|
||||||
import org.thoughtcrime.securesms.loki.protocol.MultiDeviceOpenGroupUpdateJob;
|
import org.thoughtcrime.securesms.loki.protocol.MultiDeviceOpenGroupUpdateJob;
|
||||||
import org.thoughtcrime.securesms.preferences.AppProtectionPreferenceFragment;
|
import org.thoughtcrime.securesms.preferences.AppProtectionPreferenceFragment;
|
||||||
import org.thoughtcrime.securesms.push.MessageSenderEventListener;
|
import org.thoughtcrime.securesms.push.MessageSenderEventListener;
|
||||||
@ -156,7 +156,7 @@ public class SignalCommunicationModule {
|
|||||||
DatabaseFactory.getLokiThreadDatabase(context),
|
DatabaseFactory.getLokiThreadDatabase(context),
|
||||||
DatabaseFactory.getLokiMessageDatabase(context),
|
DatabaseFactory.getLokiMessageDatabase(context),
|
||||||
DatabaseFactory.getLokiPreKeyBundleDatabase(context),
|
DatabaseFactory.getLokiPreKeyBundleDatabase(context),
|
||||||
new LokiSessionResetImplementation(context),
|
new SessionResetImplementation(context),
|
||||||
DatabaseFactory.getLokiUserDatabase(context),
|
DatabaseFactory.getLokiUserDatabase(context),
|
||||||
((ApplicationContext)context.getApplicationContext()).broadcaster);
|
((ApplicationContext)context.getApplicationContext()).broadcaster);
|
||||||
} else {
|
} else {
|
||||||
|
@ -139,7 +139,6 @@ public class MultiDeviceContactUpdateJob extends BaseJob implements InjectableTy
|
|||||||
Optional<IdentityDatabase.IdentityRecord> identityRecord = DatabaseFactory.getIdentityDatabase(context).getIdentity(address);
|
Optional<IdentityDatabase.IdentityRecord> identityRecord = DatabaseFactory.getIdentityDatabase(context).getIdentity(address);
|
||||||
Optional<VerifiedMessage> verifiedMessage = getVerifiedMessage(recipient, identityRecord);
|
Optional<VerifiedMessage> verifiedMessage = getVerifiedMessage(recipient, identityRecord);
|
||||||
|
|
||||||
// Loki - Only sync contacts we are friends with
|
|
||||||
if (SyncMessagesProtocol.shouldSyncContact(context, address)) {
|
if (SyncMessagesProtocol.shouldSyncContact(context, address)) {
|
||||||
out.write(new DeviceContact(address.toPhoneString(),
|
out.write(new DeviceContact(address.toPhoneString(),
|
||||||
Optional.fromNullable(recipient.getName()),
|
Optional.fromNullable(recipient.getName()),
|
||||||
|
@ -66,15 +66,11 @@ import org.thoughtcrime.securesms.linkpreview.LinkPreviewUtil;
|
|||||||
import org.thoughtcrime.securesms.logging.Log;
|
import org.thoughtcrime.securesms.logging.Log;
|
||||||
import org.thoughtcrime.securesms.loki.activities.HomeActivity;
|
import org.thoughtcrime.securesms.loki.activities.HomeActivity;
|
||||||
import org.thoughtcrime.securesms.loki.database.LokiMessageDatabase;
|
import org.thoughtcrime.securesms.loki.database.LokiMessageDatabase;
|
||||||
import org.thoughtcrime.securesms.loki.database.LokiThreadDatabase;
|
|
||||||
import org.thoughtcrime.securesms.loki.protocol.ClosedGroupsProtocol;
|
import org.thoughtcrime.securesms.loki.protocol.ClosedGroupsProtocol;
|
||||||
import org.thoughtcrime.securesms.loki.protocol.EphemeralMessage;
|
|
||||||
import org.thoughtcrime.securesms.loki.protocol.FriendRequestProtocol;
|
|
||||||
import org.thoughtcrime.securesms.loki.protocol.LokiSessionResetImplementation;
|
|
||||||
import org.thoughtcrime.securesms.loki.protocol.MultiDeviceProtocol;
|
import org.thoughtcrime.securesms.loki.protocol.MultiDeviceProtocol;
|
||||||
import org.thoughtcrime.securesms.loki.protocol.PushEphemeralMessageSendJob;
|
|
||||||
import org.thoughtcrime.securesms.loki.protocol.SessionManagementProtocol;
|
import org.thoughtcrime.securesms.loki.protocol.SessionManagementProtocol;
|
||||||
import org.thoughtcrime.securesms.loki.protocol.SessionMetaProtocol;
|
import org.thoughtcrime.securesms.loki.protocol.SessionMetaProtocol;
|
||||||
|
import org.thoughtcrime.securesms.loki.protocol.SessionResetImplementation;
|
||||||
import org.thoughtcrime.securesms.loki.protocol.SyncMessagesProtocol;
|
import org.thoughtcrime.securesms.loki.protocol.SyncMessagesProtocol;
|
||||||
import org.thoughtcrime.securesms.loki.utilities.MentionManagerUtilities;
|
import org.thoughtcrime.securesms.loki.utilities.MentionManagerUtilities;
|
||||||
import org.thoughtcrime.securesms.loki.utilities.PromiseUtilities;
|
import org.thoughtcrime.securesms.loki.utilities.PromiseUtilities;
|
||||||
@ -130,7 +126,6 @@ import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
|||||||
import org.whispersystems.signalservice.loki.api.fileserver.FileServerAPI;
|
import org.whispersystems.signalservice.loki.api.fileserver.FileServerAPI;
|
||||||
import org.whispersystems.signalservice.loki.crypto.LokiServiceCipher;
|
import org.whispersystems.signalservice.loki.crypto.LokiServiceCipher;
|
||||||
import org.whispersystems.signalservice.loki.protocol.mentions.MentionsManager;
|
import org.whispersystems.signalservice.loki.protocol.mentions.MentionsManager;
|
||||||
import org.whispersystems.signalservice.loki.protocol.todo.LokiThreadFriendRequestStatus;
|
|
||||||
import org.whispersystems.signalservice.loki.utilities.PublicKeyValidation;
|
import org.whispersystems.signalservice.loki.utilities.PublicKeyValidation;
|
||||||
|
|
||||||
import java.security.MessageDigest;
|
import java.security.MessageDigest;
|
||||||
@ -145,8 +140,6 @@ import javax.inject.Inject;
|
|||||||
|
|
||||||
import network.loki.messenger.R;
|
import network.loki.messenger.R;
|
||||||
|
|
||||||
import static org.thoughtcrime.securesms.loki.utilities.RecipientUtilitiesKt.recipient;
|
|
||||||
|
|
||||||
public class PushDecryptJob extends BaseJob implements InjectableType {
|
public class PushDecryptJob extends BaseJob implements InjectableType {
|
||||||
|
|
||||||
public static final String KEY = "PushDecryptJob";
|
public static final String KEY = "PushDecryptJob";
|
||||||
@ -225,9 +218,7 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCanceled() {
|
public void onCanceled() { }
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public void processMessage(@NonNull SignalServiceEnvelope envelope, boolean isPushNotification) {
|
public void processMessage(@NonNull SignalServiceEnvelope envelope, boolean isPushNotification) {
|
||||||
synchronized (PushReceivedJob.RECEIVE_LOCK) {
|
synchronized (PushReceivedJob.RECEIVE_LOCK) {
|
||||||
@ -264,18 +255,12 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
|
|||||||
try {
|
try {
|
||||||
GroupDatabase groupDatabase = DatabaseFactory.getGroupDatabase(context);
|
GroupDatabase groupDatabase = DatabaseFactory.getGroupDatabase(context);
|
||||||
SignalProtocolStore axolotlStore = new SignalProtocolStoreImpl(context);
|
SignalProtocolStore axolotlStore = new SignalProtocolStoreImpl(context);
|
||||||
SessionResetProtocol sessionResetProtocol = new LokiSessionResetImplementation(context);
|
SessionResetProtocol sessionResetProtocol = new SessionResetImplementation(context);
|
||||||
SignalServiceAddress localAddress = new SignalServiceAddress(TextSecurePreferences.getLocalNumber(context));
|
SignalServiceAddress localAddress = new SignalServiceAddress(TextSecurePreferences.getLocalNumber(context));
|
||||||
LokiServiceCipher cipher = new LokiServiceCipher(localAddress, axolotlStore, sessionResetProtocol, UnidentifiedAccessUtil.getCertificateValidator());
|
LokiServiceCipher cipher = new LokiServiceCipher(localAddress, axolotlStore, sessionResetProtocol, UnidentifiedAccessUtil.getCertificateValidator());
|
||||||
|
|
||||||
SignalServiceContent content = cipher.decrypt(envelope);
|
SignalServiceContent content = cipher.decrypt(envelope);
|
||||||
|
|
||||||
// Loki - Ignore any friend requests from before restoration
|
|
||||||
if (FriendRequestProtocol.isFriendRequestFromBeforeRestoration(context, content)) {
|
|
||||||
Log.d("Loki", "Ignoring friend request from before restoration.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (shouldIgnore(content)) {
|
if (shouldIgnore(content)) {
|
||||||
Log.i(TAG, "Ignoring message.");
|
Log.i(TAG, "Ignoring message.");
|
||||||
return;
|
return;
|
||||||
@ -300,8 +285,6 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
|
|||||||
if (message.isDeviceUnlinkingRequest()) {
|
if (message.isDeviceUnlinkingRequest()) {
|
||||||
MultiDeviceProtocol.handleUnlinkingRequestIfNeeded(context, content);
|
MultiDeviceProtocol.handleUnlinkingRequestIfNeeded(context, content);
|
||||||
} else {
|
} else {
|
||||||
// Loki - Handle friend request acceptance if needed
|
|
||||||
FriendRequestProtocol.handleFriendRequestAcceptanceIfNeeded(context, content.getSender(), content);
|
|
||||||
|
|
||||||
if (message.isEndSession()) {
|
if (message.isEndSession()) {
|
||||||
handleEndSessionMessage(content, smsMessageId);
|
handleEndSessionMessage(content, smsMessageId);
|
||||||
@ -311,14 +294,8 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
|
|||||||
handleExpirationUpdate(content, message, smsMessageId);
|
handleExpirationUpdate(content, message, smsMessageId);
|
||||||
} else if (isMediaMessage) {
|
} else if (isMediaMessage) {
|
||||||
handleMediaMessage(content, message, smsMessageId, Optional.absent());
|
handleMediaMessage(content, message, smsMessageId, Optional.absent());
|
||||||
|
|
||||||
// Loki - Handle friend request message if needed
|
|
||||||
FriendRequestProtocol.handleFriendRequestMessageIfNeeded(context, content.getSender(), content);
|
|
||||||
} else if (message.getBody().isPresent()) {
|
} else if (message.getBody().isPresent()) {
|
||||||
handleTextMessage(content, message, smsMessageId, Optional.absent());
|
handleTextMessage(content, message, smsMessageId, Optional.absent());
|
||||||
|
|
||||||
// Loki - Handle friend request message if needed
|
|
||||||
FriendRequestProtocol.handleFriendRequestMessageIfNeeded(context, content.getSender(), content);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (message.getGroupInfo().isPresent() && groupDatabase.isUnknownGroup(GroupUtil.getEncodedId(message.getGroupInfo().get()))) {
|
if (message.getGroupInfo().isPresent() && groupDatabase.isUnknownGroup(GroupUtil.getEncodedId(message.getGroupInfo().get()))) {
|
||||||
@ -364,7 +341,6 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
|
|||||||
} else if (content.getTypingMessage().isPresent()) {
|
} else if (content.getTypingMessage().isPresent()) {
|
||||||
handleTypingMessage(content, content.getTypingMessage().get());
|
handleTypingMessage(content, content.getTypingMessage().get());
|
||||||
} else if (content.getNullMessage().isPresent()) {
|
} else if (content.getNullMessage().isPresent()) {
|
||||||
|
|
||||||
// Loki - This is needed for compatibility with refactored desktop clients
|
// Loki - This is needed for compatibility with refactored desktop clients
|
||||||
// ========
|
// ========
|
||||||
// if (content.isFriendRequest()) {
|
// if (content.isFriendRequest()) {
|
||||||
@ -372,18 +348,6 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
|
|||||||
// } else {
|
// } else {
|
||||||
// Log.w(TAG, "Got unrecognized message...");
|
// Log.w(TAG, "Got unrecognized message...");
|
||||||
// }
|
// }
|
||||||
Recipient recipient = recipient(context, content.getSender());
|
|
||||||
long threadID = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipient);
|
|
||||||
LokiThreadDatabase threadDB = DatabaseFactory.getLokiThreadDatabase(context);
|
|
||||||
LokiThreadFriendRequestStatus threadFriendRequestStatus = threadDB.getFriendRequestStatus(threadID);
|
|
||||||
if (threadFriendRequestStatus == LokiThreadFriendRequestStatus.NONE || threadFriendRequestStatus == LokiThreadFriendRequestStatus.REQUEST_EXPIRED) {
|
|
||||||
threadDB.setFriendRequestStatus(threadID, LokiThreadFriendRequestStatus.REQUEST_RECEIVED);
|
|
||||||
} else if (threadFriendRequestStatus == LokiThreadFriendRequestStatus.REQUEST_SENT) {
|
|
||||||
threadDB.setFriendRequestStatus(threadID, LokiThreadFriendRequestStatus.FRIENDS);
|
|
||||||
EphemeralMessage ephemeralMessage = EphemeralMessage.create(content.getSender());
|
|
||||||
ApplicationContext.getInstance(context).getJobManager().add(new PushEphemeralMessageSendJob(ephemeralMessage));
|
|
||||||
SyncMessagesProtocol.syncContact(context, Address.fromSerialized(content.getSender()));
|
|
||||||
}
|
|
||||||
// ========
|
// ========
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,7 +2,6 @@ package org.thoughtcrime.securesms.jobs;
|
|||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.support.annotation.Nullable;
|
|
||||||
import android.support.annotation.WorkerThread;
|
import android.support.annotation.WorkerThread;
|
||||||
|
|
||||||
import com.annimon.stream.Stream;
|
import com.annimon.stream.Stream;
|
||||||
@ -31,7 +30,6 @@ import org.thoughtcrime.securesms.transport.InsecureFallbackApprovalException;
|
|||||||
import org.thoughtcrime.securesms.transport.RetryLaterException;
|
import org.thoughtcrime.securesms.transport.RetryLaterException;
|
||||||
import org.thoughtcrime.securesms.transport.UndeliverableMessageException;
|
import org.thoughtcrime.securesms.transport.UndeliverableMessageException;
|
||||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||||
import org.whispersystems.libsignal.state.PreKeyBundle;
|
|
||||||
import org.whispersystems.libsignal.util.guava.Optional;
|
import org.whispersystems.libsignal.util.guava.Optional;
|
||||||
import org.whispersystems.signalservice.api.SignalServiceMessageSender;
|
import org.whispersystems.signalservice.api.SignalServiceMessageSender;
|
||||||
import org.whispersystems.signalservice.api.crypto.UnidentifiedAccessPair;
|
import org.whispersystems.signalservice.api.crypto.UnidentifiedAccessPair;
|
||||||
@ -64,46 +62,34 @@ public class PushMediaSendJob extends PushSendJob implements InjectableType {
|
|||||||
private static final String KEY_TEMPLATE_MESSAGE_ID = "template_message_id";
|
private static final String KEY_TEMPLATE_MESSAGE_ID = "template_message_id";
|
||||||
private static final String KEY_MESSAGE_ID = "message_id";
|
private static final String KEY_MESSAGE_ID = "message_id";
|
||||||
private static final String KEY_DESTINATION = "destination";
|
private static final String KEY_DESTINATION = "destination";
|
||||||
private static final String KEY_IS_LOKI_PRE_KEY_BUNDLE_MESSAGE = "is_friend_request";
|
|
||||||
private static final String KEY_CUSTOM_FR_MESSAGE = "custom_friend_request_message";
|
|
||||||
|
|
||||||
@Inject SignalServiceMessageSender messageSender;
|
@Inject SignalServiceMessageSender messageSender;
|
||||||
|
|
||||||
private long messageId; // The message ID
|
private long messageId;
|
||||||
private long templateMessageId; // The message ID of the message to template this send job from
|
private long templateMessageId;
|
||||||
|
private Address destination;
|
||||||
// Loki - Multi device
|
|
||||||
private Address destination; // Used to check whether this is another device we're sending to
|
|
||||||
private boolean isLokiPreKeyBundleMessage; // Whether this is a friend request / session request / device link message
|
|
||||||
private String customFriendRequestMessage; // If this isn't set then we use the message body
|
|
||||||
|
|
||||||
public PushMediaSendJob(long messageId, Address destination) {
|
public PushMediaSendJob(long messageId, Address destination) {
|
||||||
this(messageId, messageId, destination);
|
this(messageId, messageId, destination);
|
||||||
}
|
}
|
||||||
|
|
||||||
public PushMediaSendJob(long templateMessageId, long messageId, Address destination) {
|
public PushMediaSendJob(long templateMessageId, long messageId, Address destination) {
|
||||||
this(templateMessageId, messageId, destination, false, null);
|
this(constructParameters(destination), templateMessageId, messageId, destination);
|
||||||
}
|
}
|
||||||
|
|
||||||
public PushMediaSendJob(long templateMessageId, long messageId, Address destination, boolean isLokiPreKeyBundleMessage, String customFriendRequestMessage) {
|
private PushMediaSendJob(@NonNull Job.Parameters parameters, long templateMessageId, long messageId, Address destination) {
|
||||||
this(constructParameters(destination), templateMessageId, messageId, destination, isLokiPreKeyBundleMessage, customFriendRequestMessage);
|
|
||||||
}
|
|
||||||
|
|
||||||
private PushMediaSendJob(@NonNull Job.Parameters parameters, long templateMessageId, long messageId, Address destination, boolean isLokiPreKeyBundleMessage, String customFriendRequestMessage) {
|
|
||||||
super(parameters);
|
super(parameters);
|
||||||
this.templateMessageId = templateMessageId;
|
this.templateMessageId = templateMessageId;
|
||||||
this.messageId = messageId;
|
this.messageId = messageId;
|
||||||
this.destination = destination;
|
this.destination = destination;
|
||||||
this.isLokiPreKeyBundleMessage = isLokiPreKeyBundleMessage;
|
|
||||||
this.customFriendRequestMessage = customFriendRequestMessage;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void enqueue(@NonNull Context context, @NonNull JobManager jobManager, long messageId, @NonNull Address destination) {
|
public static void enqueue(@NonNull Context context, @NonNull JobManager jobManager, long messageId, @NonNull Address destination) {
|
||||||
enqueue(context, jobManager, messageId, messageId, destination, false, null);
|
enqueue(context, jobManager, messageId, messageId, destination);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void enqueue(@NonNull Context context, @NonNull JobManager jobManager, long templateMessageId, long messageId, @NonNull Address destination, Boolean isFriendRequest, @Nullable String customFriendRequestMessage) {
|
public static void enqueue(@NonNull Context context, @NonNull JobManager jobManager, long templateMessageId, long messageId, @NonNull Address destination) {
|
||||||
enqueue(context, jobManager, Collections.singletonList(new PushMediaSendJob(templateMessageId, messageId, destination, isFriendRequest, customFriendRequestMessage)));
|
enqueue(context, jobManager, Collections.singletonList(new PushMediaSendJob(templateMessageId, messageId, destination)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@WorkerThread
|
@WorkerThread
|
||||||
@ -144,14 +130,10 @@ public class PushMediaSendJob extends PushSendJob implements InjectableType {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @NonNull Data serialize() {
|
public @NonNull Data serialize() {
|
||||||
Data.Builder builder = new Data.Builder()
|
return new Data.Builder()
|
||||||
.putLong(KEY_TEMPLATE_MESSAGE_ID, templateMessageId)
|
.putLong(KEY_TEMPLATE_MESSAGE_ID, templateMessageId)
|
||||||
.putLong(KEY_MESSAGE_ID, messageId)
|
.putLong(KEY_MESSAGE_ID, messageId)
|
||||||
.putString(KEY_DESTINATION, destination.serialize())
|
.putString(KEY_DESTINATION, destination.serialize()).build();
|
||||||
.putBoolean(KEY_IS_LOKI_PRE_KEY_BUNDLE_MESSAGE, isLokiPreKeyBundleMessage);
|
|
||||||
|
|
||||||
if (customFriendRequestMessage != null) { builder.putString(KEY_CUSTOM_FR_MESSAGE, customFriendRequestMessage); }
|
|
||||||
return builder.build();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -270,17 +252,8 @@ public class PushMediaSendJob extends PushSendJob implements InjectableType {
|
|||||||
List<SharedContact> sharedContacts = getSharedContactsFor(message);
|
List<SharedContact> sharedContacts = getSharedContactsFor(message);
|
||||||
List<Preview> previews = getPreviewsFor(message);
|
List<Preview> previews = getPreviewsFor(message);
|
||||||
|
|
||||||
// Loki - Include a pre key bundle if needed
|
|
||||||
PreKeyBundle preKeyBundle;
|
|
||||||
if (isLokiPreKeyBundleMessage) {
|
|
||||||
preKeyBundle = DatabaseFactory.getLokiPreKeyBundleDatabase(context).generatePreKeyBundle(address.getNumber());
|
|
||||||
} else {
|
|
||||||
preKeyBundle = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
String body = (isLokiPreKeyBundleMessage && customFriendRequestMessage != null) ? customFriendRequestMessage : message.getBody();
|
|
||||||
SignalServiceDataMessage mediaMessage = SignalServiceDataMessage.newBuilder()
|
SignalServiceDataMessage mediaMessage = SignalServiceDataMessage.newBuilder()
|
||||||
.withBody(body)
|
.withBody(message.getBody())
|
||||||
.withAttachments(serviceAttachments)
|
.withAttachments(serviceAttachments)
|
||||||
.withTimestamp(message.getSentTimeMillis())
|
.withTimestamp(message.getSentTimeMillis())
|
||||||
.withExpiration((int)(message.getExpiresIn() / 1000))
|
.withExpiration((int)(message.getExpiresIn() / 1000))
|
||||||
@ -290,7 +263,6 @@ public class PushMediaSendJob extends PushSendJob implements InjectableType {
|
|||||||
.withSharedContacts(sharedContacts)
|
.withSharedContacts(sharedContacts)
|
||||||
.withPreviews(previews)
|
.withPreviews(previews)
|
||||||
.asExpirationUpdate(message.isExpirationUpdate())
|
.asExpirationUpdate(message.isExpirationUpdate())
|
||||||
.withPreKeyBundle(preKeyBundle)
|
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
if (SessionMetaProtocol.shared.isNoteToSelf(address.getNumber())) {
|
if (SessionMetaProtocol.shared.isNoteToSelf(address.getNumber())) {
|
||||||
@ -326,9 +298,7 @@ public class PushMediaSendJob extends PushSendJob implements InjectableType {
|
|||||||
long templateMessageID = data.getLong(KEY_TEMPLATE_MESSAGE_ID);
|
long templateMessageID = data.getLong(KEY_TEMPLATE_MESSAGE_ID);
|
||||||
long messageID = data.getLong(KEY_MESSAGE_ID);
|
long messageID = data.getLong(KEY_MESSAGE_ID);
|
||||||
Address destination = Address.fromSerialized(data.getString(KEY_DESTINATION));
|
Address destination = Address.fromSerialized(data.getString(KEY_DESTINATION));
|
||||||
boolean isLokiPreKeyBundleMessage = data.getBoolean(KEY_IS_LOKI_PRE_KEY_BUNDLE_MESSAGE);
|
return new PushMediaSendJob(parameters, templateMessageID, messageID, destination);
|
||||||
String customFRMessage = data.hasString(KEY_CUSTOM_FR_MESSAGE) ? data.getString(KEY_CUSTOM_FR_MESSAGE) : null;
|
|
||||||
return new PushMediaSendJob(parameters, templateMessageID, messageID, destination, isLokiPreKeyBundleMessage, customFRMessage);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,6 @@ import org.thoughtcrime.securesms.service.ExpiringMessageManager;
|
|||||||
import org.thoughtcrime.securesms.transport.InsecureFallbackApprovalException;
|
import org.thoughtcrime.securesms.transport.InsecureFallbackApprovalException;
|
||||||
import org.thoughtcrime.securesms.transport.RetryLaterException;
|
import org.thoughtcrime.securesms.transport.RetryLaterException;
|
||||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||||
import org.whispersystems.libsignal.state.PreKeyBundle;
|
|
||||||
import org.whispersystems.libsignal.util.guava.Optional;
|
import org.whispersystems.libsignal.util.guava.Optional;
|
||||||
import org.whispersystems.signalservice.api.SignalServiceMessageSender;
|
import org.whispersystems.signalservice.api.SignalServiceMessageSender;
|
||||||
import org.whispersystems.signalservice.api.crypto.UnidentifiedAccessPair;
|
import org.whispersystems.signalservice.api.crypto.UnidentifiedAccessPair;
|
||||||
@ -47,50 +46,34 @@ public class PushTextSendJob extends PushSendJob implements InjectableType {
|
|||||||
private static final String KEY_TEMPLATE_MESSAGE_ID = "template_message_id";
|
private static final String KEY_TEMPLATE_MESSAGE_ID = "template_message_id";
|
||||||
private static final String KEY_MESSAGE_ID = "message_id";
|
private static final String KEY_MESSAGE_ID = "message_id";
|
||||||
private static final String KEY_DESTINATION = "destination";
|
private static final String KEY_DESTINATION = "destination";
|
||||||
private static final String KEY_IS_LOKI_PRE_KEY_BUNDLE_MESSAGE = "is_friend_request";
|
|
||||||
private static final String KEY_CUSTOM_FR_MESSAGE = "custom_friend_request_message";
|
|
||||||
|
|
||||||
@Inject SignalServiceMessageSender messageSender;
|
@Inject SignalServiceMessageSender messageSender;
|
||||||
|
|
||||||
private long messageId; // The message ID
|
private long messageId;
|
||||||
private long templateMessageId; // The message ID of the message to template this send job from
|
private long templateMessageId;
|
||||||
|
private Address destination;
|
||||||
// Loki - Multi device
|
|
||||||
private Address destination; // Used to check whether this is another device we're sending to
|
|
||||||
private boolean isLokiPreKeyBundleMessage; // Whether this is a friend request / session request / device link message
|
|
||||||
private String customFriendRequestMessage; // If this isn't set then we use the message body
|
|
||||||
|
|
||||||
public PushTextSendJob(long messageId, Address destination) {
|
public PushTextSendJob(long messageId, Address destination) {
|
||||||
this(messageId, messageId, destination);
|
this(messageId, messageId, destination);
|
||||||
}
|
}
|
||||||
|
|
||||||
public PushTextSendJob(long templateMessageId, long messageId, Address destination) {
|
public PushTextSendJob(long templateMessageId, long messageId, Address destination) {
|
||||||
this(templateMessageId, messageId, destination, false, null);
|
this(constructParameters(destination), templateMessageId, messageId, destination);
|
||||||
}
|
}
|
||||||
|
|
||||||
public PushTextSendJob(long templateMessageId, long messageId, Address destination, boolean isLokiPreKeyBundleMessage, String customFriendRequestMessage) {
|
private PushTextSendJob(@NonNull Job.Parameters parameters, long templateMessageId, long messageId, Address destination) {
|
||||||
this(constructParameters(destination), templateMessageId, messageId, destination, isLokiPreKeyBundleMessage, customFriendRequestMessage);
|
|
||||||
}
|
|
||||||
|
|
||||||
private PushTextSendJob(@NonNull Job.Parameters parameters, long templateMessageId, long messageId, Address destination, boolean isLokiPreKeyBundleMessage, String customFriendRequestMessage) {
|
|
||||||
super(parameters);
|
super(parameters);
|
||||||
this.templateMessageId = templateMessageId;
|
this.templateMessageId = templateMessageId;
|
||||||
this.messageId = messageId;
|
this.messageId = messageId;
|
||||||
this.destination = destination;
|
this.destination = destination;
|
||||||
this.isLokiPreKeyBundleMessage = isLokiPreKeyBundleMessage;
|
|
||||||
this.customFriendRequestMessage = customFriendRequestMessage;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @NonNull Data serialize() {
|
public @NonNull Data serialize() {
|
||||||
Data.Builder builder = new Data.Builder()
|
return new Data.Builder()
|
||||||
.putLong(KEY_TEMPLATE_MESSAGE_ID, templateMessageId)
|
.putLong(KEY_TEMPLATE_MESSAGE_ID, templateMessageId)
|
||||||
.putLong(KEY_MESSAGE_ID, messageId)
|
.putLong(KEY_MESSAGE_ID, messageId)
|
||||||
.putString(KEY_DESTINATION, destination.serialize())
|
.putString(KEY_DESTINATION, destination.serialize()).build();
|
||||||
.putBoolean(KEY_IS_LOKI_PRE_KEY_BUNDLE_MESSAGE, isLokiPreKeyBundleMessage);
|
|
||||||
|
|
||||||
if (customFriendRequestMessage != null) { builder.putString(KEY_CUSTOM_FR_MESSAGE, customFriendRequestMessage); }
|
|
||||||
return builder.build();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -213,22 +196,12 @@ public class PushTextSendJob extends PushSendJob implements InjectableType {
|
|||||||
|
|
||||||
log(TAG, "Have access key to use: " + unidentifiedAccess.isPresent());
|
log(TAG, "Have access key to use: " + unidentifiedAccess.isPresent());
|
||||||
|
|
||||||
// Loki - Include a pre key bundle if needed
|
|
||||||
PreKeyBundle preKeyBundle;
|
|
||||||
if (isLokiPreKeyBundleMessage || message.isEndSession()) {
|
|
||||||
preKeyBundle = DatabaseFactory.getLokiPreKeyBundleDatabase(context).generatePreKeyBundle(address.getNumber());
|
|
||||||
} else {
|
|
||||||
preKeyBundle = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
String body = (isLokiPreKeyBundleMessage && customFriendRequestMessage != null) ? customFriendRequestMessage : message.getBody();
|
|
||||||
SignalServiceDataMessage textSecureMessage = SignalServiceDataMessage.newBuilder()
|
SignalServiceDataMessage textSecureMessage = SignalServiceDataMessage.newBuilder()
|
||||||
.withTimestamp(message.getDateSent())
|
.withTimestamp(message.getDateSent())
|
||||||
.withBody(body)
|
.withBody(message.getBody())
|
||||||
.withExpiration((int)(message.getExpiresIn() / 1000))
|
.withExpiration((int)(message.getExpiresIn() / 1000))
|
||||||
.withProfileKey(profileKey.orNull())
|
.withProfileKey(profileKey.orNull())
|
||||||
.asEndSessionMessage(message.isEndSession())
|
.asEndSessionMessage(message.isEndSession())
|
||||||
.withPreKeyBundle(preKeyBundle)
|
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
if (SessionMetaProtocol.shared.isNoteToSelf(address.getNumber())) {
|
if (SessionMetaProtocol.shared.isNoteToSelf(address.getNumber())) {
|
||||||
@ -261,9 +234,7 @@ public class PushTextSendJob extends PushSendJob implements InjectableType {
|
|||||||
long templateMessageID = data.getLong(KEY_TEMPLATE_MESSAGE_ID);
|
long templateMessageID = data.getLong(KEY_TEMPLATE_MESSAGE_ID);
|
||||||
long messageID = data.getLong(KEY_MESSAGE_ID);
|
long messageID = data.getLong(KEY_MESSAGE_ID);
|
||||||
Address destination = Address.fromSerialized(data.getString(KEY_DESTINATION));
|
Address destination = Address.fromSerialized(data.getString(KEY_DESTINATION));
|
||||||
boolean isLokiPreKeyBundleMessage = data.getBoolean(KEY_IS_LOKI_PRE_KEY_BUNDLE_MESSAGE);
|
return new PushTextSendJob(parameters, templateMessageID, messageID, destination);
|
||||||
String customFRMessage = data.hasString(KEY_CUSTOM_FR_MESSAGE) ? data.getString(KEY_CUSTOM_FR_MESSAGE) : null;
|
|
||||||
return new PushTextSendJob(parameters, templateMessageID, messageID, destination, isLokiPreKeyBundleMessage, customFRMessage);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,9 +8,8 @@ class CreateClosedGroupLoader(context: Context) : AsyncLoader<List<String>>(cont
|
|||||||
|
|
||||||
override fun loadInBackground(): List<String> {
|
override fun loadInBackground(): List<String> {
|
||||||
val contacts = ContactUtilities.getAllContacts(context)
|
val contacts = ContactUtilities.getAllContacts(context)
|
||||||
// Only show the master devices of the users we are friends with
|
|
||||||
return contacts.filter { contact ->
|
return contacts.filter { contact ->
|
||||||
!contact.recipient.isGroupRecipient && contact.isFriend && !contact.isOurDevice && !contact.isSlave
|
!contact.recipient.isGroupRecipient && !contact.isOurDevice && !contact.isSlave
|
||||||
}.map {
|
}.map {
|
||||||
it.recipient.address.toPhoneString()
|
it.recipient.address.toPhoneString()
|
||||||
}
|
}
|
||||||
|
@ -33,7 +33,7 @@ import org.thoughtcrime.securesms.database.ThreadDatabase
|
|||||||
import org.thoughtcrime.securesms.database.model.ThreadRecord
|
import org.thoughtcrime.securesms.database.model.ThreadRecord
|
||||||
import org.thoughtcrime.securesms.loki.dialogs.PNModeBottomSheet
|
import org.thoughtcrime.securesms.loki.dialogs.PNModeBottomSheet
|
||||||
import org.thoughtcrime.securesms.loki.protocol.ClosedGroupsProtocol
|
import org.thoughtcrime.securesms.loki.protocol.ClosedGroupsProtocol
|
||||||
import org.thoughtcrime.securesms.loki.protocol.LokiSessionResetImplementation
|
import org.thoughtcrime.securesms.loki.protocol.SessionResetImplementation
|
||||||
import org.thoughtcrime.securesms.loki.utilities.*
|
import org.thoughtcrime.securesms.loki.utilities.*
|
||||||
import org.thoughtcrime.securesms.loki.views.ConversationView
|
import org.thoughtcrime.securesms.loki.views.ConversationView
|
||||||
import org.thoughtcrime.securesms.loki.views.NewConversationButtonSetViewDelegate
|
import org.thoughtcrime.securesms.loki.views.NewConversationButtonSetViewDelegate
|
||||||
@ -47,18 +47,16 @@ import org.whispersystems.signalservice.loki.protocol.meta.SessionMetaProtocol
|
|||||||
import org.whispersystems.signalservice.loki.protocol.multidevice.MultiDeviceProtocol
|
import org.whispersystems.signalservice.loki.protocol.multidevice.MultiDeviceProtocol
|
||||||
import org.whispersystems.signalservice.loki.protocol.sessionmanagement.SessionManagementProtocol
|
import org.whispersystems.signalservice.loki.protocol.sessionmanagement.SessionManagementProtocol
|
||||||
import org.whispersystems.signalservice.loki.protocol.syncmessages.SyncMessagesProtocol
|
import org.whispersystems.signalservice.loki.protocol.syncmessages.SyncMessagesProtocol
|
||||||
import org.whispersystems.signalservice.loki.protocol.todo.LokiMessageFriendRequestStatus
|
|
||||||
import org.whispersystems.signalservice.loki.protocol.todo.LokiThreadFriendRequestStatus
|
|
||||||
import kotlin.math.abs
|
import kotlin.math.abs
|
||||||
|
|
||||||
class HomeActivity : PassphraseRequiredActionBarActivity, ConversationClickListener, SeedReminderViewDelegate, NewConversationButtonSetViewDelegate {
|
class HomeActivity : PassphraseRequiredActionBarActivity, ConversationClickListener, SeedReminderViewDelegate, NewConversationButtonSetViewDelegate {
|
||||||
private lateinit var glide: GlideRequests
|
private lateinit var glide: GlideRequests
|
||||||
|
|
||||||
private val hexEncodedPublicKey: String
|
private val publicKey: String
|
||||||
get() {
|
get() {
|
||||||
val masterHexEncodedPublicKey = TextSecurePreferences.getMasterHexEncodedPublicKey(this)
|
val masterPublicKey = TextSecurePreferences.getMasterHexEncodedPublicKey(this)
|
||||||
val userHexEncodedPublicKey = TextSecurePreferences.getLocalNumber(this)
|
val userPublicKey = TextSecurePreferences.getLocalNumber(this)
|
||||||
return masterHexEncodedPublicKey ?: userHexEncodedPublicKey
|
return masterPublicKey ?: userPublicKey
|
||||||
}
|
}
|
||||||
|
|
||||||
// region Lifecycle
|
// region Lifecycle
|
||||||
@ -94,7 +92,7 @@ class HomeActivity : PassphraseRequiredActionBarActivity, ConversationClickListe
|
|||||||
glide = GlideApp.with(this)
|
glide = GlideApp.with(this)
|
||||||
// Set up toolbar buttons
|
// Set up toolbar buttons
|
||||||
profileButton.glide = glide
|
profileButton.glide = glide
|
||||||
profileButton.hexEncodedPublicKey = hexEncodedPublicKey
|
profileButton.publicKey = publicKey
|
||||||
profileButton.update()
|
profileButton.update()
|
||||||
profileButton.setOnClickListener { openSettings() }
|
profileButton.setOnClickListener { openSettings() }
|
||||||
pathStatusViewContainer.setOnClickListener { showPath() }
|
pathStatusViewContainer.setOnClickListener { showPath() }
|
||||||
@ -156,45 +154,23 @@ class HomeActivity : PassphraseRequiredActionBarActivity, ConversationClickListe
|
|||||||
val threadDB = DatabaseFactory.getLokiThreadDatabase(this)
|
val threadDB = DatabaseFactory.getLokiThreadDatabase(this)
|
||||||
val userDB = DatabaseFactory.getLokiUserDatabase(this)
|
val userDB = DatabaseFactory.getLokiUserDatabase(this)
|
||||||
val userPublicKey = TextSecurePreferences.getLocalNumber(this)
|
val userPublicKey = TextSecurePreferences.getLocalNumber(this)
|
||||||
val sessionResetImpl = LokiSessionResetImplementation(this)
|
val sessionResetImpl = SessionResetImplementation(this)
|
||||||
if (userPublicKey != null) {
|
if (userPublicKey != null) {
|
||||||
MentionsManager.configureIfNeeded(userPublicKey, threadDB, userDB)
|
MentionsManager.configureIfNeeded(userPublicKey, threadDB, userDB)
|
||||||
SessionMetaProtocol.configureIfNeeded(apiDB, userPublicKey)
|
SessionMetaProtocol.configureIfNeeded(apiDB, userPublicKey)
|
||||||
SyncMessagesProtocol.configureIfNeeded(apiDB, userPublicKey)
|
SyncMessagesProtocol.configureIfNeeded(apiDB, userPublicKey)
|
||||||
application.lokiPublicChatManager.startPollersIfNeeded()
|
application.publicChatManager.startPollersIfNeeded()
|
||||||
}
|
}
|
||||||
SessionManagementProtocol.configureIfNeeded(sessionResetImpl, threadDB, application)
|
SessionManagementProtocol.configureIfNeeded(sessionResetImpl, threadDB, application)
|
||||||
MultiDeviceProtocol.configureIfNeeded(apiDB)
|
MultiDeviceProtocol.configureIfNeeded(apiDB)
|
||||||
IP2Country.configureIfNeeded(this)
|
IP2Country.configureIfNeeded(this)
|
||||||
// Preload device links to make message sending quicker
|
// Preload device links to make message sending quicker
|
||||||
val publicKeys = ContactUtilities.getAllContacts(this).filter { contact ->
|
val publicKeys = ContactUtilities.getAllContacts(this).filter { contact ->
|
||||||
!contact.recipient.isGroupRecipient && contact.isFriend && !contact.isOurDevice && !contact.isSlave
|
!contact.recipient.isGroupRecipient && !contact.isOurDevice && !contact.isSlave
|
||||||
}.map {
|
}.map {
|
||||||
it.recipient.address.toPhoneString()
|
it.recipient.address.toPhoneString()
|
||||||
}.toSet()
|
}.toSet()
|
||||||
FileServerAPI.shared.getDeviceLinks(publicKeys)
|
FileServerAPI.shared.getDeviceLinks(publicKeys)
|
||||||
// TODO: Temporary hack to unbork existing clients
|
|
||||||
val allContacts = DatabaseFactory.getRecipientDatabase(this).allAddresses.map {
|
|
||||||
MultiDeviceProtocol.shared.getMasterDevice(it.serialize()) ?: it.serialize()
|
|
||||||
}.toSet()
|
|
||||||
val lokiMessageDB = DatabaseFactory.getLokiMessageDatabase(this)
|
|
||||||
for (contact in allContacts) {
|
|
||||||
val slaveDeviceHasPendingFR = MultiDeviceProtocol.shared.getSlaveDevices(contact).any {
|
|
||||||
val slaveDeviceThreadID = DatabaseFactory.getThreadDatabase(this).getThreadIdFor(recipient(this, it))
|
|
||||||
DatabaseFactory.getLokiThreadDatabase(this).getFriendRequestStatus(slaveDeviceThreadID) == LokiThreadFriendRequestStatus.REQUEST_RECEIVED
|
|
||||||
}
|
|
||||||
val masterDeviceThreadID = DatabaseFactory.getThreadDatabase(this).getThreadIdFor(recipient(this, contact))
|
|
||||||
val masterDeviceHasNoPendingFR = (DatabaseFactory.getLokiThreadDatabase(this).getFriendRequestStatus(masterDeviceThreadID) == LokiThreadFriendRequestStatus.NONE)
|
|
||||||
if (slaveDeviceHasPendingFR && masterDeviceHasNoPendingFR) {
|
|
||||||
val lastMessageID = org.thoughtcrime.securesms.loki.protocol.FriendRequestProtocol.getLastMessageID(this, masterDeviceThreadID)
|
|
||||||
if (lastMessageID != null) {
|
|
||||||
val lastMessageFRStatus = lokiMessageDB.getFriendRequestStatus(lastMessageID)
|
|
||||||
if (lastMessageFRStatus != LokiMessageFriendRequestStatus.REQUEST_PENDING) {
|
|
||||||
lokiMessageDB.setFriendRequestStatus(lastMessageID, LokiMessageFriendRequestStatus.REQUEST_PENDING)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
|
@ -15,7 +15,7 @@ import org.thoughtcrime.securesms.database.IdentityDatabase
|
|||||||
import org.thoughtcrime.securesms.logging.Log
|
import org.thoughtcrime.securesms.logging.Log
|
||||||
import org.thoughtcrime.securesms.loki.dialogs.LinkDeviceSlaveModeDialog
|
import org.thoughtcrime.securesms.loki.dialogs.LinkDeviceSlaveModeDialog
|
||||||
import org.thoughtcrime.securesms.loki.dialogs.LinkDeviceSlaveModeDialogDelegate
|
import org.thoughtcrime.securesms.loki.dialogs.LinkDeviceSlaveModeDialogDelegate
|
||||||
import org.thoughtcrime.securesms.loki.protocol.LokiSessionResetImplementation
|
import org.thoughtcrime.securesms.loki.protocol.SessionResetImplementation
|
||||||
import org.thoughtcrime.securesms.loki.protocol.MultiDeviceProtocol
|
import org.thoughtcrime.securesms.loki.protocol.MultiDeviceProtocol
|
||||||
import org.thoughtcrime.securesms.loki.utilities.push
|
import org.thoughtcrime.securesms.loki.utilities.push
|
||||||
import org.thoughtcrime.securesms.loki.utilities.setUpActionBarSessionLogo
|
import org.thoughtcrime.securesms.loki.utilities.setUpActionBarSessionLogo
|
||||||
@ -109,7 +109,7 @@ class LandingActivity : BaseActionBarActivity(), LinkDeviceSlaveModeDialogDelega
|
|||||||
val threadDB = DatabaseFactory.getLokiThreadDatabase(this)
|
val threadDB = DatabaseFactory.getLokiThreadDatabase(this)
|
||||||
val userDB = DatabaseFactory.getLokiUserDatabase(this)
|
val userDB = DatabaseFactory.getLokiUserDatabase(this)
|
||||||
val userPublicKey = TextSecurePreferences.getLocalNumber(this)
|
val userPublicKey = TextSecurePreferences.getLocalNumber(this)
|
||||||
val sessionResetImpl = LokiSessionResetImplementation(this)
|
val sessionResetImpl = SessionResetImplementation(this)
|
||||||
MentionsManager.configureIfNeeded(userPublicKey, threadDB, userDB)
|
MentionsManager.configureIfNeeded(userPublicKey, threadDB, userDB)
|
||||||
SessionMetaProtocol.configureIfNeeded(apiDB, userPublicKey)
|
SessionMetaProtocol.configureIfNeeded(apiDB, userPublicKey)
|
||||||
org.whispersystems.signalservice.loki.protocol.multidevice.MultiDeviceProtocol.configureIfNeeded(apiDB)
|
org.whispersystems.signalservice.loki.protocol.multidevice.MultiDeviceProtocol.configureIfNeeded(apiDB)
|
||||||
|
@ -73,7 +73,7 @@ class SettingsActivity : PassphraseRequiredActionBarActivity() {
|
|||||||
showQRCodeButton.setOnClickListener { showQRCode() }
|
showQRCodeButton.setOnClickListener { showQRCode() }
|
||||||
glide = GlideApp.with(this)
|
glide = GlideApp.with(this)
|
||||||
profilePictureView.glide = glide
|
profilePictureView.glide = glide
|
||||||
profilePictureView.hexEncodedPublicKey = hexEncodedPublicKey
|
profilePictureView.publicKey = hexEncodedPublicKey
|
||||||
profilePictureView.isLarge = true
|
profilePictureView.isLarge = true
|
||||||
profilePictureView.update()
|
profilePictureView.update()
|
||||||
profilePictureView.setOnClickListener { showEditProfilePictureUI() }
|
profilePictureView.setOnClickListener { showEditProfilePictureUI() }
|
||||||
|
@ -47,7 +47,7 @@ class BackgroundPollWorker : PersistentAlarmManagerListener() {
|
|||||||
}
|
}
|
||||||
val openGroups = DatabaseFactory.getLokiThreadDatabase(context).getAllPublicChats().map { it.value }
|
val openGroups = DatabaseFactory.getLokiThreadDatabase(context).getAllPublicChats().map { it.value }
|
||||||
for (openGroup in openGroups) {
|
for (openGroup in openGroups) {
|
||||||
val poller = LokiPublicChatPoller(context, openGroup)
|
val poller = PublicChatPoller(context, openGroup)
|
||||||
poller.stop()
|
poller.stop()
|
||||||
poller.pollForNewMessages()
|
poller.pollForNewMessages()
|
||||||
}
|
}
|
||||||
|
@ -14,9 +14,9 @@ import org.thoughtcrime.securesms.util.TextSecurePreferences
|
|||||||
import org.thoughtcrime.securesms.util.Util
|
import org.thoughtcrime.securesms.util.Util
|
||||||
import org.whispersystems.signalservice.loki.api.opengroups.PublicChat
|
import org.whispersystems.signalservice.loki.api.opengroups.PublicChat
|
||||||
|
|
||||||
class LokiPublicChatManager(private val context: Context) {
|
class PublicChatManager(private val context: Context) {
|
||||||
private var chats = mutableMapOf<Long, PublicChat>()
|
private var chats = mutableMapOf<Long, PublicChat>()
|
||||||
private val pollers = mutableMapOf<Long, LokiPublicChatPoller>()
|
private val pollers = mutableMapOf<Long, PublicChatPoller>()
|
||||||
private val observers = mutableMapOf<Long, ContentObserver>()
|
private val observers = mutableMapOf<Long, ContentObserver>()
|
||||||
private var isPolling = false
|
private var isPolling = false
|
||||||
|
|
||||||
@ -24,7 +24,7 @@ class LokiPublicChatManager(private val context: Context) {
|
|||||||
var areAllCaughtUp = true
|
var areAllCaughtUp = true
|
||||||
refreshChatsAndPollers()
|
refreshChatsAndPollers()
|
||||||
for ((threadID, chat) in chats) {
|
for ((threadID, chat) in chats) {
|
||||||
val poller = pollers[threadID] ?: LokiPublicChatPoller(context, chat)
|
val poller = pollers[threadID] ?: PublicChatPoller(context, chat)
|
||||||
areAllCaughtUp = areAllCaughtUp && poller.isCaughtUp
|
areAllCaughtUp = areAllCaughtUp && poller.isCaughtUp
|
||||||
}
|
}
|
||||||
return areAllCaughtUp
|
return areAllCaughtUp
|
||||||
@ -33,7 +33,7 @@ class LokiPublicChatManager(private val context: Context) {
|
|||||||
public fun markAllAsNotCaughtUp() {
|
public fun markAllAsNotCaughtUp() {
|
||||||
refreshChatsAndPollers()
|
refreshChatsAndPollers()
|
||||||
for ((threadID, chat) in chats) {
|
for ((threadID, chat) in chats) {
|
||||||
val poller = pollers[threadID] ?: LokiPublicChatPoller(context, chat)
|
val poller = pollers[threadID] ?: PublicChatPoller(context, chat)
|
||||||
poller.isCaughtUp = false
|
poller.isCaughtUp = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -42,7 +42,7 @@ class LokiPublicChatManager(private val context: Context) {
|
|||||||
refreshChatsAndPollers()
|
refreshChatsAndPollers()
|
||||||
|
|
||||||
for ((threadId, chat) in chats) {
|
for ((threadId, chat) in chats) {
|
||||||
val poller = pollers[threadId] ?: LokiPublicChatPoller(context, chat)
|
val poller = pollers[threadId] ?: PublicChatPoller(context, chat)
|
||||||
poller.startIfNeeded()
|
poller.startIfNeeded()
|
||||||
listenToThreadDeletion(threadId)
|
listenToThreadDeletion(threadId)
|
||||||
if (!pollers.containsKey(threadId)) { pollers[threadId] = poller }
|
if (!pollers.containsKey(threadId)) { pollers[threadId] = poller }
|
@ -27,11 +27,10 @@ import org.whispersystems.signalservice.loki.api.opengroups.PublicChat
|
|||||||
import org.whispersystems.signalservice.loki.api.opengroups.PublicChatAPI
|
import org.whispersystems.signalservice.loki.api.opengroups.PublicChatAPI
|
||||||
import org.whispersystems.signalservice.loki.api.opengroups.PublicChatMessage
|
import org.whispersystems.signalservice.loki.api.opengroups.PublicChatMessage
|
||||||
import org.whispersystems.signalservice.loki.protocol.multidevice.MultiDeviceProtocol
|
import org.whispersystems.signalservice.loki.protocol.multidevice.MultiDeviceProtocol
|
||||||
import org.whispersystems.signalservice.loki.protocol.todo.LokiThreadFriendRequestStatus
|
|
||||||
import java.security.MessageDigest
|
import java.security.MessageDigest
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
class LokiPublicChatPoller(private val context: Context, private val group: PublicChat) {
|
class PublicChatPoller(private val context: Context, private val group: PublicChat) {
|
||||||
private val handler = Handler()
|
private val handler = Handler()
|
||||||
private var hasStarted = false
|
private var hasStarted = false
|
||||||
public var isCaughtUp = false
|
public var isCaughtUp = false
|
||||||
@ -182,13 +181,6 @@ class LokiPublicChatPoller(private val context: Context, private val group: Publ
|
|||||||
database.setProfileKey(senderAsRecipient, profileKey)
|
database.setProfileKey(senderAsRecipient, profileKey)
|
||||||
ApplicationContext.getInstance(context).jobManager.add(RetrieveProfileAvatarJob(senderAsRecipient, url))
|
ApplicationContext.getInstance(context).jobManager.add(RetrieveProfileAvatarJob(senderAsRecipient, url))
|
||||||
}
|
}
|
||||||
} else if (senderAsRecipient.profileAvatar.orEmpty().isNotEmpty()) {
|
|
||||||
// Clear the profile picture if we had a profile picture before and we're not friends with the person
|
|
||||||
val threadID = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(senderAsRecipient)
|
|
||||||
val friendRequestStatus = DatabaseFactory.getLokiThreadDatabase(context).getFriendRequestStatus(threadID)
|
|
||||||
if (friendRequestStatus != LokiThreadFriendRequestStatus.FRIENDS) {
|
|
||||||
ApplicationContext.getInstance(context).jobManager.add(RetrieveProfileAvatarJob(senderAsRecipient, ""))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fun processOutgoingMessage(message: PublicChatMessage) {
|
fun processOutgoingMessage(message: PublicChatMessage) {
|
@ -11,12 +11,11 @@ import org.thoughtcrime.securesms.loki.utilities.getInt
|
|||||||
import org.thoughtcrime.securesms.loki.utilities.getString
|
import org.thoughtcrime.securesms.loki.utilities.getString
|
||||||
import org.thoughtcrime.securesms.loki.utilities.insertOrUpdate
|
import org.thoughtcrime.securesms.loki.utilities.insertOrUpdate
|
||||||
import org.whispersystems.signalservice.loki.database.LokiMessageDatabaseProtocol
|
import org.whispersystems.signalservice.loki.database.LokiMessageDatabaseProtocol
|
||||||
import org.whispersystems.signalservice.loki.protocol.todo.LokiMessageFriendRequestStatus
|
|
||||||
|
|
||||||
class LokiMessageDatabase(context: Context, helper: SQLCipherOpenHelper) : Database(context, helper), LokiMessageDatabaseProtocol {
|
class LokiMessageDatabase(context: Context, helper: SQLCipherOpenHelper) : Database(context, helper), LokiMessageDatabaseProtocol {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val messageFriendRequestTable = "loki_message_friend_request_database"
|
private val messageIDTable = "loki_message_friend_request_database"
|
||||||
private val messageThreadMappingTable = "loki_message_thread_mapping_database"
|
private val messageThreadMappingTable = "loki_message_thread_mapping_database"
|
||||||
private val errorMessageTable = "loki_error_message_database"
|
private val errorMessageTable = "loki_error_message_database"
|
||||||
private val messageID = "message_id"
|
private val messageID = "message_id"
|
||||||
@ -24,7 +23,7 @@ class LokiMessageDatabase(context: Context, helper: SQLCipherOpenHelper) : Datab
|
|||||||
private val friendRequestStatus = "friend_request_status"
|
private val friendRequestStatus = "friend_request_status"
|
||||||
private val threadID = "thread_id"
|
private val threadID = "thread_id"
|
||||||
private val errorMessage = "error_message"
|
private val errorMessage = "error_message"
|
||||||
@JvmStatic val createMessageFriendRequestTableCommand = "CREATE TABLE $messageFriendRequestTable ($messageID INTEGER PRIMARY KEY, $serverID INTEGER DEFAULT 0, $friendRequestStatus INTEGER DEFAULT 0);"
|
@JvmStatic val createMessageIDTableCommand = "CREATE TABLE $messageIDTable ($messageID INTEGER PRIMARY KEY, $serverID INTEGER DEFAULT 0, $friendRequestStatus INTEGER DEFAULT 0);"
|
||||||
@JvmStatic val createMessageToThreadMappingTableCommand = "CREATE TABLE IF NOT EXISTS $messageThreadMappingTable ($messageID INTEGER PRIMARY KEY, $threadID INTEGER);"
|
@JvmStatic val createMessageToThreadMappingTableCommand = "CREATE TABLE IF NOT EXISTS $messageThreadMappingTable ($messageID INTEGER PRIMARY KEY, $threadID INTEGER);"
|
||||||
@JvmStatic val createErrorMessageTableCommand = "CREATE TABLE IF NOT EXISTS $errorMessageTable ($messageID INTEGER PRIMARY KEY, $errorMessage STRING);"
|
@JvmStatic val createErrorMessageTableCommand = "CREATE TABLE IF NOT EXISTS $errorMessageTable ($messageID INTEGER PRIMARY KEY, $errorMessage STRING);"
|
||||||
}
|
}
|
||||||
@ -36,14 +35,14 @@ class LokiMessageDatabase(context: Context, helper: SQLCipherOpenHelper) : Datab
|
|||||||
|
|
||||||
fun getServerID(messageID: Long): Long? {
|
fun getServerID(messageID: Long): Long? {
|
||||||
val database = databaseHelper.readableDatabase
|
val database = databaseHelper.readableDatabase
|
||||||
return database.get(messageFriendRequestTable, "${Companion.messageID} = ?", arrayOf( messageID.toString() )) { cursor ->
|
return database.get(messageIDTable, "${Companion.messageID} = ?", arrayOf( messageID.toString() )) { cursor ->
|
||||||
cursor.getInt(serverID)
|
cursor.getInt(serverID)
|
||||||
}?.toLong()
|
}?.toLong()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getMessageID(serverID: Long): Long? {
|
fun getMessageID(serverID: Long): Long? {
|
||||||
val database = databaseHelper.readableDatabase
|
val database = databaseHelper.readableDatabase
|
||||||
return database.get(messageFriendRequestTable, "${Companion.serverID} = ?", arrayOf( serverID.toString() )) { cursor ->
|
return database.get(messageIDTable, "${Companion.serverID} = ?", arrayOf( serverID.toString() )) { cursor ->
|
||||||
cursor.getInt(messageID)
|
cursor.getInt(messageID)
|
||||||
}?.toLong()
|
}?.toLong()
|
||||||
}
|
}
|
||||||
@ -53,7 +52,7 @@ class LokiMessageDatabase(context: Context, helper: SQLCipherOpenHelper) : Datab
|
|||||||
val contentValues = ContentValues(2)
|
val contentValues = ContentValues(2)
|
||||||
contentValues.put(Companion.messageID, messageID)
|
contentValues.put(Companion.messageID, messageID)
|
||||||
contentValues.put(Companion.serverID, serverID)
|
contentValues.put(Companion.serverID, serverID)
|
||||||
database.insertOrUpdate(messageFriendRequestTable, contentValues, "${Companion.messageID} = ?", arrayOf( messageID.toString() ))
|
database.insertOrUpdate(messageIDTable, contentValues, "${Companion.messageID} = ?", arrayOf( messageID.toString() ))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getOriginalThreadID(messageID: Long): Long {
|
fun getOriginalThreadID(messageID: Long): Long {
|
||||||
@ -71,32 +70,6 @@ class LokiMessageDatabase(context: Context, helper: SQLCipherOpenHelper) : Datab
|
|||||||
database.insertOrUpdate(messageThreadMappingTable, contentValues, "${Companion.messageID} = ?", arrayOf( messageID.toString() ))
|
database.insertOrUpdate(messageThreadMappingTable, contentValues, "${Companion.messageID} = ?", arrayOf( messageID.toString() ))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getFriendRequestStatus(messageID: Long): LokiMessageFriendRequestStatus {
|
|
||||||
val database = databaseHelper.readableDatabase
|
|
||||||
val result = database.get(messageFriendRequestTable, "${Companion.messageID} = ?", arrayOf( messageID.toString() )) { cursor ->
|
|
||||||
cursor.getInt(friendRequestStatus)
|
|
||||||
}
|
|
||||||
return if (result != null) {
|
|
||||||
LokiMessageFriendRequestStatus.values().first { it.rawValue == result }
|
|
||||||
} else {
|
|
||||||
LokiMessageFriendRequestStatus.NONE
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun setFriendRequestStatus(messageID: Long, friendRequestStatus: LokiMessageFriendRequestStatus) {
|
|
||||||
val database = databaseHelper.writableDatabase
|
|
||||||
val contentValues = ContentValues(2)
|
|
||||||
contentValues.put(Companion.messageID, messageID)
|
|
||||||
contentValues.put(Companion.friendRequestStatus, friendRequestStatus.rawValue)
|
|
||||||
database.insertOrUpdate(messageFriendRequestTable, contentValues, "${Companion.messageID} = ?", arrayOf( messageID.toString() ))
|
|
||||||
val threadID = DatabaseFactory.getSmsDatabase(context).getThreadIdForMessage(messageID)
|
|
||||||
notifyConversationListeners(threadID)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun isFriendRequest(messageID: Long): Boolean {
|
|
||||||
return getFriendRequestStatus(messageID) != LokiMessageFriendRequestStatus.NONE
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getErrorMessage(messageID: Long): String? {
|
fun getErrorMessage(messageID: Long): String? {
|
||||||
val database = databaseHelper.readableDatabase
|
val database = databaseHelper.readableDatabase
|
||||||
return database.get(errorMessageTable, "${Companion.messageID} = ?", arrayOf( messageID.toString() )) { cursor ->
|
return database.get(errorMessageTable, "${Companion.messageID} = ?", arrayOf( messageID.toString() )) { cursor ->
|
||||||
|
@ -15,21 +15,18 @@ import org.whispersystems.libsignal.loki.SessionResetStatus
|
|||||||
import org.whispersystems.signalservice.internal.util.JsonUtil
|
import org.whispersystems.signalservice.internal.util.JsonUtil
|
||||||
import org.whispersystems.signalservice.loki.api.opengroups.PublicChat
|
import org.whispersystems.signalservice.loki.api.opengroups.PublicChat
|
||||||
import org.whispersystems.signalservice.loki.database.LokiThreadDatabaseProtocol
|
import org.whispersystems.signalservice.loki.database.LokiThreadDatabaseProtocol
|
||||||
import org.whispersystems.signalservice.loki.protocol.todo.LokiThreadFriendRequestStatus
|
|
||||||
import org.whispersystems.signalservice.loki.utilities.PublicKeyValidation
|
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
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val friendRequestTable = "loki_thread_friend_request_database"
|
|
||||||
private val sessionResetTable = "loki_thread_session_reset_database"
|
private val sessionResetTable = "loki_thread_session_reset_database"
|
||||||
val publicChatTable = "loki_public_chat_database"
|
val publicChatTable = "loki_public_chat_database"
|
||||||
val threadID = "thread_id"
|
val threadID = "thread_id"
|
||||||
private val friendRequestStatus = "friend_request_status"
|
private val friendRequestStatus = "friend_request_status"
|
||||||
private val sessionResetStatus = "session_reset_status"
|
private val sessionResetStatus = "session_reset_status"
|
||||||
val publicChat = "public_chat"
|
val publicChat = "public_chat"
|
||||||
@JvmStatic val createFriendRequestTableCommand = "CREATE TABLE $friendRequestTable ($threadID INTEGER PRIMARY KEY, $friendRequestStatus INTEGER DEFAULT 0);"
|
|
||||||
@JvmStatic val createSessionResetTableCommand = "CREATE TABLE $sessionResetTable ($threadID INTEGER PRIMARY KEY, $sessionResetStatus INTEGER DEFAULT 0);"
|
@JvmStatic val createSessionResetTableCommand = "CREATE TABLE $sessionResetTable ($threadID INTEGER PRIMARY KEY, $sessionResetStatus INTEGER DEFAULT 0);"
|
||||||
@JvmStatic val createPublicChatTableCommand = "CREATE TABLE $publicChatTable ($threadID INTEGER PRIMARY KEY, $publicChat TEXT);"
|
@JvmStatic val createPublicChatTableCommand = "CREATE TABLE $publicChatTable ($threadID INTEGER PRIMARY KEY, $publicChat TEXT);"
|
||||||
}
|
}
|
||||||
@ -44,34 +41,6 @@ class LokiThreadDatabase(context: Context, helper: SQLCipherOpenHelper) : Databa
|
|||||||
return DatabaseFactory.getSmsDatabase(context).getThreadIdForMessage(messageID)
|
return DatabaseFactory.getSmsDatabase(context).getThreadIdForMessage(messageID)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getFriendRequestStatus(threadID: Long): LokiThreadFriendRequestStatus {
|
|
||||||
if (threadID < 0) { return LokiThreadFriendRequestStatus.NONE }
|
|
||||||
val recipient = DatabaseFactory.getThreadDatabase(context).getRecipientForThreadId(threadID)
|
|
||||||
if (recipient != null && recipient.isGroupRecipient) { return LokiThreadFriendRequestStatus.FRIENDS; }
|
|
||||||
val database = databaseHelper.readableDatabase
|
|
||||||
val result = database.get(friendRequestTable, "${Companion.threadID} = ?", arrayOf( threadID.toString() )) { cursor ->
|
|
||||||
cursor.getInt(friendRequestStatus)
|
|
||||||
}
|
|
||||||
return if (result != null) {
|
|
||||||
LokiThreadFriendRequestStatus.values().first { it.rawValue == result }
|
|
||||||
} else {
|
|
||||||
LokiThreadFriendRequestStatus.NONE
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun setFriendRequestStatus(threadID: Long, friendRequestStatus: LokiThreadFriendRequestStatus) {
|
|
||||||
if (threadID < 0) { return }
|
|
||||||
Log.d("Loki", "Setting FR status for thread with ID $threadID to $friendRequestStatus.")
|
|
||||||
val database = databaseHelper.writableDatabase
|
|
||||||
val contentValues = ContentValues(2)
|
|
||||||
contentValues.put(Companion.threadID, threadID)
|
|
||||||
contentValues.put(Companion.friendRequestStatus, friendRequestStatus.rawValue)
|
|
||||||
database.insertOrUpdate(friendRequestTable, contentValues, "${Companion.threadID} = ?", arrayOf( threadID.toString() ))
|
|
||||||
notifyConversationListListeners()
|
|
||||||
notifyConversationListeners(threadID)
|
|
||||||
delegate?.handleThreadFriendRequestStatusChanged(threadID)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getSessionResetStatus(hexEncodedPublicKey: String): SessionResetStatus {
|
fun getSessionResetStatus(hexEncodedPublicKey: String): SessionResetStatus {
|
||||||
val threadID = getThreadID(hexEncodedPublicKey)
|
val threadID = getThreadID(hexEncodedPublicKey)
|
||||||
val database = databaseHelper.readableDatabase
|
val database = databaseHelper.readableDatabase
|
||||||
|
@ -2,6 +2,5 @@ package org.thoughtcrime.securesms.loki.database
|
|||||||
|
|
||||||
interface LokiThreadDatabaseDelegate {
|
interface LokiThreadDatabaseDelegate {
|
||||||
|
|
||||||
fun handleThreadFriendRequestStatusChanged(threadID: Long)
|
|
||||||
fun handleSessionRestoreDevicesChanged(threadID: Long)
|
fun handleSessionRestoreDevicesChanged(threadID: Long)
|
||||||
}
|
}
|
@ -15,10 +15,10 @@ sealed class ContactSelectionListItem {
|
|||||||
class ContactSelectionListLoader(context: Context, val mode: Int, val filter: String?) : AsyncLoader<List<ContactSelectionListItem>>(context) {
|
class ContactSelectionListLoader(context: Context, val mode: Int, val filter: String?) : AsyncLoader<List<ContactSelectionListItem>>(context) {
|
||||||
|
|
||||||
object DisplayMode {
|
object DisplayMode {
|
||||||
const val FLAG_FRIENDS = 1
|
const val FLAG_CONTACTS = 1
|
||||||
const val FLAG_CLOSED_GROUPS = 1 shl 1
|
const val FLAG_CLOSED_GROUPS = 1 shl 1
|
||||||
const val FLAG_OPEN_GROUPS = 1 shl 2
|
const val FLAG_OPEN_GROUPS = 1 shl 2
|
||||||
const val FLAG_ALL = FLAG_FRIENDS or FLAG_CLOSED_GROUPS or FLAG_OPEN_GROUPS
|
const val FLAG_ALL = FLAG_CONTACTS or FLAG_CLOSED_GROUPS or FLAG_OPEN_GROUPS
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun isFlagSet(flag: Int): Boolean {
|
private fun isFlagSet(flag: Int): Boolean {
|
||||||
@ -39,15 +39,15 @@ class ContactSelectionListLoader(context: Context, val mode: Int, val filter: St
|
|||||||
if (isFlagSet(DisplayMode.FLAG_OPEN_GROUPS)) {
|
if (isFlagSet(DisplayMode.FLAG_OPEN_GROUPS)) {
|
||||||
list.addAll(getOpenGroups(contacts))
|
list.addAll(getOpenGroups(contacts))
|
||||||
}
|
}
|
||||||
if (isFlagSet(DisplayMode.FLAG_FRIENDS)) {
|
if (isFlagSet(DisplayMode.FLAG_CONTACTS)) {
|
||||||
list.addAll(getFriends(contacts))
|
list.addAll(getContacts(contacts))
|
||||||
}
|
}
|
||||||
return list
|
return list
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getFriends(contacts: List<Contact>): List<ContactSelectionListItem> {
|
private fun getContacts(contacts: List<Contact>): List<ContactSelectionListItem> {
|
||||||
return getItems(contacts, context.getString(R.string.fragment_contact_selection_contacts_title)) {
|
return getItems(contacts, context.getString(R.string.fragment_contact_selection_contacts_title)) {
|
||||||
!it.recipient.isGroupRecipient && it.isFriend && !it.isOurDevice && !it.isSlave
|
!it.recipient.isGroupRecipient && !it.isOurDevice && !it.isSlave
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,10 +10,7 @@ class EphemeralMessage private constructor(val data: Map<*, *>) {
|
|||||||
fun create(publicKey: String) = EphemeralMessage(mapOf( "recipient" to publicKey ))
|
fun create(publicKey: String) = EphemeralMessage(mapOf( "recipient" to publicKey ))
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun createUnlinkingRequest(publicKey: String) = EphemeralMessage(mapOf( "recipient" to publicKey, "unpairingRequest" to true ))
|
fun createDeviceUnlinkingRequest(publicKey: String) = EphemeralMessage(mapOf( "recipient" to publicKey, "unpairingRequest" to true ))
|
||||||
|
|
||||||
@JvmStatic
|
|
||||||
fun createSessionRestorationRequest(publicKey: String) = EphemeralMessage(mapOf( "recipient" to publicKey, "friendRequest" to true, "sessionRestore" to true ))
|
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun createSessionRequest(publicKey: String) = EphemeralMessage(mapOf( "recipient" to publicKey, "friendRequest" to true, "sessionRequest" to true ))
|
fun createSessionRequest(publicKey: String) = EphemeralMessage(mapOf( "recipient" to publicKey, "friendRequest" to true, "sessionRequest" to true ))
|
||||||
|
@ -1,316 +0,0 @@
|
|||||||
package org.thoughtcrime.securesms.loki.protocol
|
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import android.util.Log
|
|
||||||
import org.thoughtcrime.securesms.ApplicationContext
|
|
||||||
import org.thoughtcrime.securesms.database.Address
|
|
||||||
import org.thoughtcrime.securesms.database.DatabaseFactory
|
|
||||||
import org.thoughtcrime.securesms.loki.utilities.recipient
|
|
||||||
import org.thoughtcrime.securesms.mms.OutgoingMediaMessage
|
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient
|
|
||||||
import org.thoughtcrime.securesms.sms.MessageSender
|
|
||||||
import org.thoughtcrime.securesms.sms.OutgoingEncryptedMessage
|
|
||||||
import org.thoughtcrime.securesms.sms.OutgoingTextMessage
|
|
||||||
import org.thoughtcrime.securesms.util.TextSecurePreferences
|
|
||||||
import org.whispersystems.signalservice.api.messages.SignalServiceContent
|
|
||||||
import org.whispersystems.signalservice.loki.protocol.meta.SessionMetaProtocol
|
|
||||||
import org.whispersystems.signalservice.loki.protocol.multidevice.MultiDeviceProtocol
|
|
||||||
import org.whispersystems.signalservice.loki.protocol.todo.LokiMessageFriendRequestStatus
|
|
||||||
import org.whispersystems.signalservice.loki.protocol.todo.LokiThreadFriendRequestStatus
|
|
||||||
|
|
||||||
object FriendRequestProtocol {
|
|
||||||
|
|
||||||
@JvmStatic
|
|
||||||
fun acceptFriendRequest(context: Context, recipient: Recipient) {
|
|
||||||
if (recipient.isGroupRecipient) { return; }
|
|
||||||
val userPublicKey = TextSecurePreferences.getLocalNumber(context)
|
|
||||||
val allUserDevices = MultiDeviceProtocol.shared.getAllLinkedDevices(userPublicKey)
|
|
||||||
// Accept all outstanding friend requests associated with this user and try to establish sessions with the
|
|
||||||
// subset of their devices that haven't sent a friend request.
|
|
||||||
val allContactDevices = MultiDeviceProtocol.shared.getAllLinkedDevices(recipient.address.serialize())
|
|
||||||
val threadDB = DatabaseFactory.getThreadDatabase(context)
|
|
||||||
val lokiThreadDB = DatabaseFactory.getLokiThreadDatabase(context)
|
|
||||||
for (device in allContactDevices) {
|
|
||||||
val deviceAsRecipient = recipient(context, device)
|
|
||||||
val deviceThreadID = threadDB.getThreadIdFor(deviceAsRecipient)
|
|
||||||
val deviceFRStatus = lokiThreadDB.getFriendRequestStatus(deviceThreadID)
|
|
||||||
if (deviceFRStatus == LokiThreadFriendRequestStatus.REQUEST_RECEIVED) {
|
|
||||||
lokiThreadDB.setFriendRequestStatus(deviceThreadID, LokiThreadFriendRequestStatus.FRIENDS)
|
|
||||||
val lastMessageID = getLastMessageID(context, deviceThreadID)
|
|
||||||
if (lastMessageID != null) {
|
|
||||||
DatabaseFactory.getLokiMessageDatabase(context).setFriendRequestStatus(lastMessageID, LokiMessageFriendRequestStatus.REQUEST_ACCEPTED)
|
|
||||||
}
|
|
||||||
DatabaseFactory.getRecipientDatabase(context).setProfileSharing(recipient(context, device), true)
|
|
||||||
val ephemeralMessage = EphemeralMessage.create(device)
|
|
||||||
ApplicationContext.getInstance(context).jobManager.add(PushEphemeralMessageSendJob(ephemeralMessage))
|
|
||||||
// Sync contact if needed
|
|
||||||
if (allUserDevices.contains(device)) { return }
|
|
||||||
val deviceToSync = MultiDeviceProtocol.shared.getMasterDevice(device) ?: device
|
|
||||||
SyncMessagesProtocol.syncContact(context, Address.fromSerialized(deviceToSync))
|
|
||||||
} else if (deviceFRStatus == LokiThreadFriendRequestStatus.REQUEST_SENT) {
|
|
||||||
// Do nothing
|
|
||||||
} else if (!allUserDevices.contains(device)
|
|
||||||
&& (deviceFRStatus == LokiThreadFriendRequestStatus.NONE || deviceFRStatus == LokiThreadFriendRequestStatus.REQUEST_EXPIRED)) {
|
|
||||||
sendAutoGeneratedFriendRequest(context, device)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@JvmStatic
|
|
||||||
fun rejectFriendRequest(context: Context, recipient: Recipient) {
|
|
||||||
if (recipient.isGroupRecipient) { return; }
|
|
||||||
val linkedDevices = MultiDeviceProtocol.shared.getAllLinkedDevices(recipient.address.serialize())
|
|
||||||
val threadDB = DatabaseFactory.getThreadDatabase(context)
|
|
||||||
val lokiThreadDB = DatabaseFactory.getLokiThreadDatabase(context)
|
|
||||||
for (device in linkedDevices) {
|
|
||||||
val deviceAsRecipient = recipient(context, device)
|
|
||||||
val deviceThreadID = threadDB.getThreadIdFor(deviceAsRecipient)
|
|
||||||
val deviceFRStatus = lokiThreadDB.getFriendRequestStatus(deviceThreadID)
|
|
||||||
// We only want to decline incoming requests
|
|
||||||
if (deviceFRStatus == LokiThreadFriendRequestStatus.REQUEST_RECEIVED) {
|
|
||||||
// Delete the pre key bundle for the given contact. This ensures that if we send a
|
|
||||||
// new message after this, it restarts the friend request process from scratch.
|
|
||||||
DatabaseFactory.getLokiPreKeyBundleDatabase(context).removePreKeyBundle(device)
|
|
||||||
lokiThreadDB.setFriendRequestStatus(deviceThreadID, LokiThreadFriendRequestStatus.NONE)
|
|
||||||
val lastMessageID = getLastMessageID(context, deviceThreadID)
|
|
||||||
if (lastMessageID != null) {
|
|
||||||
DatabaseFactory.getLokiMessageDatabase(context).setFriendRequestStatus(lastMessageID, LokiMessageFriendRequestStatus.REQUEST_REJECTED)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@JvmStatic
|
|
||||||
fun shouldInputPanelBeEnabled(context: Context, recipient: Recipient): Boolean {
|
|
||||||
// Friend requests have nothing to do with groups, so if this is a group thread the input panel should be enabled
|
|
||||||
if (recipient.isGroupRecipient) { return true }
|
|
||||||
// If this is a note to self the input panel should be enabled
|
|
||||||
if (SessionMetaProtocol.shared.isNoteToSelf(recipient.address.serialize())) { return true }
|
|
||||||
// Gather friend request statuses
|
|
||||||
val linkedDeviceFRStatuses = mutableSetOf<LokiThreadFriendRequestStatus>()
|
|
||||||
val linkedDevices = MultiDeviceProtocol.shared.getAllLinkedDevices(recipient.address.serialize())
|
|
||||||
val threadDB = DatabaseFactory.getThreadDatabase(context)
|
|
||||||
val lokiThreadDB = DatabaseFactory.getLokiThreadDatabase(context)
|
|
||||||
for (device in linkedDevices) {
|
|
||||||
val deviceAsRecipient = recipient(context, device)
|
|
||||||
val deviceThreadID = threadDB.getThreadIdFor(deviceAsRecipient)
|
|
||||||
val deviceFRStatus = lokiThreadDB.getFriendRequestStatus(deviceThreadID)
|
|
||||||
linkedDeviceFRStatuses.add(deviceFRStatus)
|
|
||||||
}
|
|
||||||
// If the user is friends with any of the other user's devices the input panel should be enabled
|
|
||||||
if (linkedDeviceFRStatuses.contains(LokiThreadFriendRequestStatus.FRIENDS)) { return true }
|
|
||||||
// If no friend request has been sent the input panel should be enabled
|
|
||||||
if (linkedDeviceFRStatuses.all { it == LokiThreadFriendRequestStatus.NONE || it == LokiThreadFriendRequestStatus.REQUEST_EXPIRED }) { return true }
|
|
||||||
// There must be a pending friend request
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
@JvmStatic
|
|
||||||
fun shouldAttachmentButtonBeEnabled(context: Context, recipient: Recipient): Boolean {
|
|
||||||
// Friend requests have nothing to do with groups, so if this is a group thread the attachment button should be enabled
|
|
||||||
if (recipient.isGroupRecipient) { return true }
|
|
||||||
// If this is a note to self the attachment button should be enabled
|
|
||||||
if (SessionMetaProtocol.shared.isNoteToSelf(recipient.address.serialize())) { return true }
|
|
||||||
// Gather friend request statuses
|
|
||||||
val linkedDeviceFRStatuses = mutableSetOf<LokiThreadFriendRequestStatus>()
|
|
||||||
val linkedDevices = MultiDeviceProtocol.shared.getAllLinkedDevices(recipient.address.serialize())
|
|
||||||
val threadDB = DatabaseFactory.getThreadDatabase(context)
|
|
||||||
val lokiThreadDB = DatabaseFactory.getLokiThreadDatabase(context)
|
|
||||||
for (device in linkedDevices) {
|
|
||||||
val deviceAsRecipient = recipient(context, device)
|
|
||||||
val deviceThreadID = threadDB.getThreadIdFor(deviceAsRecipient)
|
|
||||||
val deviceFRStatus = lokiThreadDB.getFriendRequestStatus(deviceThreadID)
|
|
||||||
linkedDeviceFRStatuses.add(deviceFRStatus)
|
|
||||||
}
|
|
||||||
// If the user is friends with any of the other user's devices the attachment button should be enabled
|
|
||||||
if (linkedDeviceFRStatuses.contains(LokiThreadFriendRequestStatus.FRIENDS)) { return true }
|
|
||||||
// Otherwise don't allow attachments
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
@JvmStatic
|
|
||||||
fun getLastMessageID(context: Context, threadID: Long): Long? {
|
|
||||||
val db = DatabaseFactory.getSmsDatabase(context)
|
|
||||||
val messageCount = db.getMessageCountForThread(threadID)
|
|
||||||
if (messageCount == 0) { return null }
|
|
||||||
return db.getIDForMessageAtIndex(threadID, messageCount - 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
@JvmStatic
|
|
||||||
fun handleFriendRequestAcceptanceIfNeeded(context: Context, publicKey: String, content: SignalServiceContent) {
|
|
||||||
// If we get an envelope that isn't a friend request, then we can infer that we had to use
|
|
||||||
// Signal cipher decryption and thus that we have a session with the other person.
|
|
||||||
val recipient = recipient(context, publicKey)
|
|
||||||
// Friend requests don't apply to groups
|
|
||||||
if (recipient.isGroupRecipient) { return }
|
|
||||||
val threadID = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipient)
|
|
||||||
val lokiThreadDB = DatabaseFactory.getLokiThreadDatabase(context)
|
|
||||||
val threadFRStatus = lokiThreadDB.getFriendRequestStatus(threadID)
|
|
||||||
// Guard against invalid state transitions
|
|
||||||
if (threadFRStatus != LokiThreadFriendRequestStatus.REQUEST_SENDING && threadFRStatus != LokiThreadFriendRequestStatus.REQUEST_SENT
|
|
||||||
&& threadFRStatus != LokiThreadFriendRequestStatus.REQUEST_RECEIVED) { return }
|
|
||||||
Log.d("Loki", "Received a friend request accepted message from $publicKey.")
|
|
||||||
lokiThreadDB.setFriendRequestStatus(threadID, LokiThreadFriendRequestStatus.FRIENDS)
|
|
||||||
val lastMessageID = getLastMessageID(context, threadID)
|
|
||||||
if (lastMessageID != null) {
|
|
||||||
DatabaseFactory.getLokiMessageDatabase(context).setFriendRequestStatus(lastMessageID, LokiMessageFriendRequestStatus.REQUEST_ACCEPTED)
|
|
||||||
}
|
|
||||||
DatabaseFactory.getRecipientDatabase(context).setProfileSharing(recipient, true)
|
|
||||||
// Send a contact sync message if needed
|
|
||||||
val userPublicKey = TextSecurePreferences.getLocalNumber(context)
|
|
||||||
val allUserDevices = MultiDeviceProtocol.shared.getAllLinkedDevices(userPublicKey)
|
|
||||||
if (allUserDevices.contains(publicKey)) { return }
|
|
||||||
val deviceToSync = MultiDeviceProtocol.shared.getMasterDevice(publicKey) ?: publicKey
|
|
||||||
SyncMessagesProtocol.syncContact(context, Address.fromSerialized(deviceToSync))
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun canFriendRequestBeAutoAccepted(context: Context, publicKey: String): Boolean {
|
|
||||||
val recipient = recipient(context, publicKey)
|
|
||||||
val threadID = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipient)
|
|
||||||
val lokiThreadDB = DatabaseFactory.getLokiThreadDatabase(context)
|
|
||||||
val threadFRStatus = lokiThreadDB.getFriendRequestStatus(threadID)
|
|
||||||
if (threadFRStatus == LokiThreadFriendRequestStatus.REQUEST_SENT) {
|
|
||||||
// This can happen if Alice sent Bob a friend request, Bob declined, but then Bob changed his
|
|
||||||
// mind and sent a friend request to Alice. In this case we want Alice to auto-accept the request
|
|
||||||
// and send a friend request accepted message back to Bob. We don't check that sending the
|
|
||||||
// friend request accepted message succeeds. Even if it doesn't, the thread's current friend
|
|
||||||
// request status will be set to FRIENDS for Alice making it possible for Alice to send messages
|
|
||||||
// to Bob. When Bob receives a message, his thread's friend request status will then be set to
|
|
||||||
// FRIENDS. If we do check for a successful send before updating Alice's thread's friend request
|
|
||||||
// status to FRIENDS, we can end up in a deadlock where both users' threads' friend request statuses
|
|
||||||
// are SENT.
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
// Auto-accept any friend requests from the user's own linked devices
|
|
||||||
val userPublicKey = TextSecurePreferences.getLocalNumber(context)
|
|
||||||
val allUserDevices = MultiDeviceProtocol.shared.getAllLinkedDevices(userPublicKey)
|
|
||||||
if (allUserDevices.contains(publicKey)) { return true }
|
|
||||||
// Auto-accept if the user is friends with any of the sender's linked devices.
|
|
||||||
val allSenderDevices = MultiDeviceProtocol.shared.getAllLinkedDevices(publicKey)
|
|
||||||
if (allSenderDevices.any { device ->
|
|
||||||
val deviceAsRecipient = recipient(context, publicKey)
|
|
||||||
val deviceThreadID = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(deviceAsRecipient)
|
|
||||||
lokiThreadDB.getFriendRequestStatus(deviceThreadID) == LokiThreadFriendRequestStatus.FRIENDS
|
|
||||||
}) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
@JvmStatic
|
|
||||||
fun handleFriendRequestMessageIfNeeded(context: Context, publicKey: String, content: SignalServiceContent) {
|
|
||||||
val recipient = recipient(context, publicKey)
|
|
||||||
// Friend requests don't apply to groups
|
|
||||||
if (recipient.isGroupRecipient) { return }
|
|
||||||
val threadID = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipient)
|
|
||||||
val lokiThreadDB = DatabaseFactory.getLokiThreadDatabase(context)
|
|
||||||
val threadFRStatus = lokiThreadDB.getFriendRequestStatus(threadID)
|
|
||||||
if (canFriendRequestBeAutoAccepted(context, publicKey)) {
|
|
||||||
Log.d("Loki", "Auto-accepting friend request from $publicKey.")
|
|
||||||
lokiThreadDB.setFriendRequestStatus(threadID, LokiThreadFriendRequestStatus.FRIENDS)
|
|
||||||
val lastMessageID = getLastMessageID(context, threadID)
|
|
||||||
if (lastMessageID != null) {
|
|
||||||
DatabaseFactory.getLokiMessageDatabase(context).setFriendRequestStatus(lastMessageID, LokiMessageFriendRequestStatus.REQUEST_ACCEPTED)
|
|
||||||
}
|
|
||||||
DatabaseFactory.getRecipientDatabase(context).setProfileSharing(recipient, true)
|
|
||||||
val ephemeralMessage = EphemeralMessage.create(publicKey)
|
|
||||||
ApplicationContext.getInstance(context).jobManager.add(PushEphemeralMessageSendJob(ephemeralMessage))
|
|
||||||
} else if (threadFRStatus != LokiThreadFriendRequestStatus.FRIENDS) {
|
|
||||||
Log.d("Loki", "Handling friend request from $publicKey.")
|
|
||||||
// Checking that the sender of the message isn't already a friend is necessary because otherwise
|
|
||||||
// the following situation can occur: Alice and Bob are friends. Bob loses his database and his
|
|
||||||
// friend request status is reset to NONE. Bob now sends Alice a friend request. Alice's thread's
|
|
||||||
// friend request status is reset to RECEIVED
|
|
||||||
lokiThreadDB.setFriendRequestStatus(threadID, LokiThreadFriendRequestStatus.REQUEST_RECEIVED)
|
|
||||||
val masterPublicKey = MultiDeviceProtocol.shared.getMasterDevice(publicKey) ?: publicKey
|
|
||||||
val masterThreadID = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipient(context, masterPublicKey))
|
|
||||||
val masterThreadLastMessageID = getLastMessageID(context, masterThreadID) // Messages get routed into the master thread
|
|
||||||
if (masterThreadLastMessageID != null) {
|
|
||||||
DatabaseFactory.getLokiMessageDatabase(context).setFriendRequestStatus(masterThreadLastMessageID, LokiMessageFriendRequestStatus.REQUEST_PENDING)
|
|
||||||
} else {
|
|
||||||
// Device link fetching could fail, in which case the message could get routed into the slave thread
|
|
||||||
val slaveThreadLastMessageID = getLastMessageID(context, threadID)
|
|
||||||
if (slaveThreadLastMessageID != null) {
|
|
||||||
DatabaseFactory.getLokiMessageDatabase(context).setFriendRequestStatus(slaveThreadLastMessageID, LokiMessageFriendRequestStatus.REQUEST_PENDING)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@JvmStatic
|
|
||||||
fun isFriendRequestFromBeforeRestoration(context: Context, content: SignalServiceContent): Boolean {
|
|
||||||
return content.timestamp < TextSecurePreferences.getRestorationTime(context)
|
|
||||||
}
|
|
||||||
|
|
||||||
@JvmStatic
|
|
||||||
fun shouldUpdateFriendRequestStatusFromOutgoingTextMessage(context: Context, message: OutgoingTextMessage): Boolean {
|
|
||||||
// The order of these checks matters
|
|
||||||
if (message.recipient.isGroupRecipient) { return false }
|
|
||||||
if (message.recipient.address.serialize() == TextSecurePreferences.getLocalNumber(context)) { return false }
|
|
||||||
// TODO: Return true if the message is a device linking request
|
|
||||||
// TODO: Return false if the message is a session request
|
|
||||||
return message.isFriendRequest
|
|
||||||
}
|
|
||||||
|
|
||||||
@JvmStatic
|
|
||||||
fun shouldUpdateFriendRequestStatusFromOutgoingMediaMessage(context: Context, message: OutgoingMediaMessage): Boolean {
|
|
||||||
// The order of these checks matters
|
|
||||||
if (message.recipient.isGroupRecipient) { return false }
|
|
||||||
if (message.recipient.address.serialize() == TextSecurePreferences.getLocalNumber(context)) { return false }
|
|
||||||
// TODO: Return true if the message is a device linking request
|
|
||||||
// TODO: Return false if the message is a session request
|
|
||||||
return message.isFriendRequest
|
|
||||||
}
|
|
||||||
|
|
||||||
@JvmStatic
|
|
||||||
fun setFriendRequestStatusToSendingIfNeeded(context: Context, messageID: Long, threadID: Long) {
|
|
||||||
val messageDB = DatabaseFactory.getLokiMessageDatabase(context)
|
|
||||||
val messageFRStatus = messageDB.getFriendRequestStatus(messageID)
|
|
||||||
if (messageFRStatus == LokiMessageFriendRequestStatus.NONE || messageFRStatus == LokiMessageFriendRequestStatus.REQUEST_EXPIRED) {
|
|
||||||
messageDB.setFriendRequestStatus(messageID, LokiMessageFriendRequestStatus.REQUEST_SENDING)
|
|
||||||
}
|
|
||||||
val threadDB = DatabaseFactory.getLokiThreadDatabase(context)
|
|
||||||
val threadFRStatus = threadDB.getFriendRequestStatus(threadID)
|
|
||||||
if (threadFRStatus == LokiThreadFriendRequestStatus.NONE || threadFRStatus == LokiThreadFriendRequestStatus.REQUEST_EXPIRED) {
|
|
||||||
threadDB.setFriendRequestStatus(threadID, LokiThreadFriendRequestStatus.REQUEST_SENDING)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@JvmStatic
|
|
||||||
fun setFriendRequestStatusToSentIfNeeded(context: Context, messageID: Long, threadID: Long) {
|
|
||||||
val messageDB = DatabaseFactory.getLokiMessageDatabase(context)
|
|
||||||
val messageFRStatus = messageDB.getFriendRequestStatus(messageID)
|
|
||||||
if (messageFRStatus == LokiMessageFriendRequestStatus.NONE || messageFRStatus == LokiMessageFriendRequestStatus.REQUEST_EXPIRED
|
|
||||||
|| messageFRStatus == LokiMessageFriendRequestStatus.REQUEST_SENDING) {
|
|
||||||
messageDB.setFriendRequestStatus(messageID, LokiMessageFriendRequestStatus.REQUEST_PENDING)
|
|
||||||
}
|
|
||||||
val threadDB = DatabaseFactory.getLokiThreadDatabase(context)
|
|
||||||
val threadFRStatus = threadDB.getFriendRequestStatus(threadID)
|
|
||||||
if (threadFRStatus == LokiThreadFriendRequestStatus.NONE || threadFRStatus == LokiThreadFriendRequestStatus.REQUEST_EXPIRED
|
|
||||||
|| threadFRStatus == LokiThreadFriendRequestStatus.REQUEST_SENDING) {
|
|
||||||
threadDB.setFriendRequestStatus(threadID, LokiThreadFriendRequestStatus.REQUEST_SENT)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@JvmStatic
|
|
||||||
fun setFriendRequestStatusToFailedIfNeeded(context: Context, messageID: Long, threadID: Long) {
|
|
||||||
val messageDB = DatabaseFactory.getLokiMessageDatabase(context)
|
|
||||||
val messageFRStatus = messageDB.getFriendRequestStatus(messageID)
|
|
||||||
if (messageFRStatus == LokiMessageFriendRequestStatus.REQUEST_SENDING) {
|
|
||||||
messageDB.setFriendRequestStatus(messageID, LokiMessageFriendRequestStatus.REQUEST_FAILED)
|
|
||||||
}
|
|
||||||
val threadDB = DatabaseFactory.getLokiThreadDatabase(context)
|
|
||||||
val threadFRStatus = threadDB.getFriendRequestStatus(threadID)
|
|
||||||
if (threadFRStatus == LokiThreadFriendRequestStatus.REQUEST_SENDING) {
|
|
||||||
threadDB.setFriendRequestStatus(threadID, LokiThreadFriendRequestStatus.NONE)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun sendAutoGeneratedFriendRequest(context: Context, publicKey: String) {
|
|
||||||
val recipient = recipient(context, publicKey)
|
|
||||||
val message = OutgoingEncryptedMessage(recipient, "Please accept to enable messages to be synced across devices", 0)
|
|
||||||
message.isFriendRequest = true
|
|
||||||
val threadID = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipient)
|
|
||||||
MessageSender.send(context, message, threadID, false, null)
|
|
||||||
}
|
|
||||||
}
|
|
@ -23,7 +23,6 @@ import org.whispersystems.signalservice.loki.protocol.meta.SessionMetaProtocol
|
|||||||
import org.whispersystems.signalservice.loki.protocol.multidevice.DeviceLink
|
import org.whispersystems.signalservice.loki.protocol.multidevice.DeviceLink
|
||||||
import org.whispersystems.signalservice.loki.protocol.multidevice.DeviceLinkingSession
|
import org.whispersystems.signalservice.loki.protocol.multidevice.DeviceLinkingSession
|
||||||
import org.whispersystems.signalservice.loki.protocol.multidevice.MultiDeviceProtocol
|
import org.whispersystems.signalservice.loki.protocol.multidevice.MultiDeviceProtocol
|
||||||
import org.whispersystems.signalservice.loki.protocol.todo.LokiThreadFriendRequestStatus
|
|
||||||
import org.whispersystems.signalservice.loki.utilities.retryIfNeeded
|
import org.whispersystems.signalservice.loki.utilities.retryIfNeeded
|
||||||
|
|
||||||
object MultiDeviceProtocol {
|
object MultiDeviceProtocol {
|
||||||
@ -40,36 +39,6 @@ object MultiDeviceProtocol {
|
|||||||
sendMessagePush(context, recipient, messageID, MessageType.Media, false)
|
sendMessagePush(context, recipient, messageID, MessageType.Media, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun sendMessagePushToDevice(context: Context, recipient: Recipient, messageID: Long, messageType: MessageType, isEndSession: Boolean): PushSendJob {
|
|
||||||
val threadID = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipient)
|
|
||||||
val threadFRStatus = DatabaseFactory.getLokiThreadDatabase(context).getFriendRequestStatus(threadID)
|
|
||||||
val isNoteToSelf = SessionMetaProtocol.shared.isNoteToSelf(recipient.address.serialize())
|
|
||||||
val isContactFriend = (threadFRStatus == LokiThreadFriendRequestStatus.FRIENDS || isNoteToSelf) // In the note to self case the device linking request was the FR
|
|
||||||
val isFRMessage = !isContactFriend
|
|
||||||
val hasVisibleContent = when (messageType) {
|
|
||||||
MessageType.Text -> DatabaseFactory.getSmsDatabase(context).getMessage(messageID).body.isNotBlank()
|
|
||||||
MessageType.Media -> {
|
|
||||||
val outgoingMediaMessage = DatabaseFactory.getMmsDatabase(context).getOutgoingMessage(messageID)
|
|
||||||
outgoingMediaMessage.body.isNotBlank() || outgoingMediaMessage.attachments.isNotEmpty()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
val shouldSendAutoGeneratedFR = !isContactFriend && !isFRMessage
|
|
||||||
&& !isNoteToSelf && !recipient.address.isGroup // Group threads work through session requests
|
|
||||||
&& hasVisibleContent && !isEndSession
|
|
||||||
if (!shouldSendAutoGeneratedFR) {
|
|
||||||
when (messageType) {
|
|
||||||
MessageType.Text -> return PushTextSendJob(messageID, messageID, recipient.address, isFRMessage, null)
|
|
||||||
MessageType.Media -> return PushMediaSendJob(messageID, messageID, recipient.address, isFRMessage, null)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
val autoGeneratedFRMessage = "Please accept to enable messages to be synced across devices"
|
|
||||||
when (messageType) {
|
|
||||||
MessageType.Text -> return PushTextSendJob(messageID, messageID, recipient.address, true, autoGeneratedFRMessage)
|
|
||||||
MessageType.Media -> return PushMediaSendJob(messageID, messageID, recipient.address, true, autoGeneratedFRMessage)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun sendMessagePush(context: Context, recipient: Recipient, messageID: Long, messageType: MessageType, isEndSession: Boolean) {
|
private fun sendMessagePush(context: Context, recipient: Recipient, messageID: Long, messageType: MessageType, isEndSession: Boolean) {
|
||||||
val jobManager = ApplicationContext.getInstance(context).jobManager
|
val jobManager = ApplicationContext.getInstance(context).jobManager
|
||||||
val isMultiDeviceRequired = !recipient.address.isOpenGroup
|
val isMultiDeviceRequired = !recipient.address.isOpenGroup
|
||||||
@ -82,7 +51,12 @@ object MultiDeviceProtocol {
|
|||||||
val publicKey = recipient.address.serialize()
|
val publicKey = recipient.address.serialize()
|
||||||
FileServerAPI.shared.getDeviceLinks(publicKey).success {
|
FileServerAPI.shared.getDeviceLinks(publicKey).success {
|
||||||
val devices = MultiDeviceProtocol.shared.getAllLinkedDevices(publicKey)
|
val devices = MultiDeviceProtocol.shared.getAllLinkedDevices(publicKey)
|
||||||
val jobs = devices.map { sendMessagePushToDevice(context, recipient(context, it), messageID, messageType, isEndSession) }
|
val jobs = devices.map {
|
||||||
|
when (messageType) {
|
||||||
|
MessageType.Text -> PushTextSendJob(messageID, messageID, recipient(context, it).address) as PushSendJob
|
||||||
|
MessageType.Media -> PushMediaSendJob(messageID, messageID, recipient(context, it).address) as PushSendJob
|
||||||
|
}
|
||||||
|
}
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
when (messageType) {
|
when (messageType) {
|
||||||
MessageType.Text -> jobManager.startChain(jobs).enqueue()
|
MessageType.Text -> jobManager.startChain(jobs).enqueue()
|
||||||
|
@ -27,8 +27,8 @@ object SessionManagementProtocol {
|
|||||||
val smsDB = DatabaseFactory.getSmsDatabase(context)
|
val smsDB = DatabaseFactory.getSmsDatabase(context)
|
||||||
val devices = lokiThreadDB.getSessionRestoreDevices(threadID)
|
val devices = lokiThreadDB.getSessionRestoreDevices(threadID)
|
||||||
for (device in devices) {
|
for (device in devices) {
|
||||||
val sessionRestorationRequest = EphemeralMessage.createSessionRestorationRequest(recipient.address.serialize())
|
val sessionRequest = EphemeralMessage.createSessionRequest(recipient.address.serialize())
|
||||||
ApplicationContext.getInstance(context).jobManager.add(PushEphemeralMessageSendJob(sessionRestorationRequest))
|
ApplicationContext.getInstance(context).jobManager.add(PushEphemeralMessageSendJob(sessionRequest))
|
||||||
}
|
}
|
||||||
val infoMessage = OutgoingTextMessage(recipient, "", 0, 0)
|
val infoMessage = OutgoingTextMessage(recipient, "", 0, 0)
|
||||||
val infoMessageID = smsDB.insertMessageOutbox(threadID, infoMessage, false, System.currentTimeMillis(), null)
|
val infoMessageID = smsDB.insertMessageOutbox(threadID, infoMessage, false, System.currentTimeMillis(), null)
|
||||||
|
@ -11,7 +11,6 @@ import org.thoughtcrime.securesms.util.TextSecurePreferences
|
|||||||
import org.whispersystems.signalservice.api.messages.SignalServiceContent
|
import org.whispersystems.signalservice.api.messages.SignalServiceContent
|
||||||
import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage
|
import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage
|
||||||
import org.whispersystems.signalservice.loki.protocol.multidevice.MultiDeviceProtocol
|
import org.whispersystems.signalservice.loki.protocol.multidevice.MultiDeviceProtocol
|
||||||
import org.whispersystems.signalservice.loki.protocol.todo.LokiThreadFriendRequestStatus
|
|
||||||
import java.security.MessageDigest
|
import java.security.MessageDigest
|
||||||
|
|
||||||
object SessionMetaProtocol {
|
object SessionMetaProtocol {
|
||||||
@ -75,31 +74,23 @@ object SessionMetaProtocol {
|
|||||||
* Should be invoked for the recipient's master device.
|
* Should be invoked for the recipient's master device.
|
||||||
*/
|
*/
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun canUserReplyToNotification(recipient: Recipient, context: Context): Boolean {
|
fun canUserReplyToNotification(recipient: Recipient): Boolean {
|
||||||
val isGroup = recipient.isGroupRecipient
|
return !recipient.address.isRSSFeed
|
||||||
if (isGroup) { return !recipient.address.isRSSFeed }
|
|
||||||
val threadID = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipient)
|
|
||||||
return DatabaseFactory.getLokiThreadDatabase(context).getFriendRequestStatus(threadID) == LokiThreadFriendRequestStatus.FRIENDS
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Should be invoked for the recipient's master device.
|
* Should be invoked for the recipient's master device.
|
||||||
*/
|
*/
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun shouldSendReadReceipt(address: Address, context: Context): Boolean {
|
fun shouldSendReadReceipt(address: Address): Boolean {
|
||||||
if (address.isGroup) { return false }
|
return !address.isGroup
|
||||||
val recipient = Recipient.from(context, address,false)
|
|
||||||
val threadID = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipient)
|
|
||||||
return DatabaseFactory.getLokiThreadDatabase(context).getFriendRequestStatus(threadID) == LokiThreadFriendRequestStatus.FRIENDS
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Should be invoked for the recipient's master device.
|
* Should be invoked for the recipient's master device.
|
||||||
*/
|
*/
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun shouldSendTypingIndicator(recipient: Recipient?, context: Context): Boolean {
|
fun shouldSendTypingIndicator(address: Address): Boolean {
|
||||||
if (recipient == null || recipient.isGroupRecipient) { return false }
|
return !address.isGroup
|
||||||
val threadID = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipient)
|
|
||||||
return DatabaseFactory.getLokiThreadDatabase(context).getFriendRequestStatus(threadID) == LokiThreadFriendRequestStatus.FRIENDS
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -7,7 +7,7 @@ import org.whispersystems.libsignal.loki.SessionResetProtocol
|
|||||||
import org.whispersystems.libsignal.loki.SessionResetStatus
|
import org.whispersystems.libsignal.loki.SessionResetStatus
|
||||||
import org.whispersystems.libsignal.protocol.PreKeySignalMessage
|
import org.whispersystems.libsignal.protocol.PreKeySignalMessage
|
||||||
|
|
||||||
class LokiSessionResetImplementation(private val context: Context) : SessionResetProtocol {
|
class SessionResetImplementation(private val context: Context) : SessionResetProtocol {
|
||||||
|
|
||||||
override fun getSessionResetStatus(publicKey: String): SessionResetStatus {
|
override fun getSessionResetStatus(publicKey: String): SessionResetStatus {
|
||||||
return DatabaseFactory.getLokiThreadDatabase(context).getSessionResetStatus(publicKey)
|
return DatabaseFactory.getLokiThreadDatabase(context).getSessionResetStatus(publicKey)
|
@ -24,8 +24,6 @@ import org.whispersystems.signalservice.api.messages.multidevice.DeviceContactsI
|
|||||||
import org.whispersystems.signalservice.api.messages.multidevice.DeviceGroupsInputStream
|
import org.whispersystems.signalservice.api.messages.multidevice.DeviceGroupsInputStream
|
||||||
import org.whispersystems.signalservice.loki.api.opengroups.PublicChat
|
import org.whispersystems.signalservice.loki.api.opengroups.PublicChat
|
||||||
import org.whispersystems.signalservice.loki.protocol.multidevice.MultiDeviceProtocol
|
import org.whispersystems.signalservice.loki.protocol.multidevice.MultiDeviceProtocol
|
||||||
import org.whispersystems.signalservice.loki.protocol.todo.LokiMessageFriendRequestStatus
|
|
||||||
import org.whispersystems.signalservice.loki.protocol.todo.LokiThreadFriendRequestStatus
|
|
||||||
import org.whispersystems.signalservice.loki.utilities.PublicKeyValidation
|
import org.whispersystems.signalservice.loki.utilities.PublicKeyValidation
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
@ -67,9 +65,7 @@ object SyncMessagesProtocol {
|
|||||||
if (!PublicKeyValidation.isValid(address.serialize())) { return false }
|
if (!PublicKeyValidation.isValid(address.serialize())) { return false }
|
||||||
if (address.serialize() == TextSecurePreferences.getMasterHexEncodedPublicKey(context)) { return false }
|
if (address.serialize() == TextSecurePreferences.getMasterHexEncodedPublicKey(context)) { return false }
|
||||||
if (address.serialize() == TextSecurePreferences.getLocalNumber(context)) { return false }
|
if (address.serialize() == TextSecurePreferences.getLocalNumber(context)) { return false }
|
||||||
val threadID = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(Recipient.from(context, address, false))
|
return true
|
||||||
val isFriend = DatabaseFactory.getLokiThreadDatabase(context).getFriendRequestStatus(threadID) == LokiThreadFriendRequestStatus.FRIENDS
|
|
||||||
return isFriend
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
@ -99,29 +95,9 @@ object SyncMessagesProtocol {
|
|||||||
for (contactPublicKey in contactPublicKeys) {
|
for (contactPublicKey in contactPublicKeys) {
|
||||||
if (contactPublicKey == userPublicKey || !PublicKeyValidation.isValid(contactPublicKey)) { return }
|
if (contactPublicKey == userPublicKey || !PublicKeyValidation.isValid(contactPublicKey)) { return }
|
||||||
val recipient = recipient(context, contactPublicKey)
|
val recipient = recipient(context, contactPublicKey)
|
||||||
val threadID = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipient)
|
val applicationContext = context.applicationContext as ApplicationContext
|
||||||
val lokiThreadDB = DatabaseFactory.getLokiThreadDatabase(context)
|
applicationContext.sendSessionRequestIfNeeded(contactPublicKey)
|
||||||
val threadFRStatus = lokiThreadDB.getFriendRequestStatus(threadID)
|
// TODO: Make the thread visible
|
||||||
when (threadFRStatus) {
|
|
||||||
LokiThreadFriendRequestStatus.NONE, LokiThreadFriendRequestStatus.REQUEST_EXPIRED -> {
|
|
||||||
val contactLinkedDevices = MultiDeviceProtocol.shared.getAllLinkedDevices(contactPublicKey)
|
|
||||||
for (device in contactLinkedDevices) {
|
|
||||||
FriendRequestProtocol.sendAutoGeneratedFriendRequest(context, device)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
LokiThreadFriendRequestStatus.REQUEST_RECEIVED -> {
|
|
||||||
FriendRequestProtocol.acceptFriendRequest(context, recipient(context, contactPublicKey)) // Takes into account multi device internally
|
|
||||||
lokiThreadDB.setFriendRequestStatus(threadID, LokiThreadFriendRequestStatus.FRIENDS)
|
|
||||||
val lastMessageID = FriendRequestProtocol.getLastMessageID(context, threadID)
|
|
||||||
if (lastMessageID != null) {
|
|
||||||
DatabaseFactory.getLokiMessageDatabase(context).setFriendRequestStatus(lastMessageID, LokiMessageFriendRequestStatus.REQUEST_ACCEPTED)
|
|
||||||
}
|
|
||||||
DatabaseFactory.getRecipientDatabase(context).setProfileSharing(recipient(context, contactPublicKey), true)
|
|
||||||
}
|
|
||||||
else -> {
|
|
||||||
// Do nothing
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,11 +5,9 @@ import org.thoughtcrime.securesms.database.DatabaseFactory
|
|||||||
import org.thoughtcrime.securesms.recipients.Recipient
|
import org.thoughtcrime.securesms.recipients.Recipient
|
||||||
import org.thoughtcrime.securesms.util.TextSecurePreferences
|
import org.thoughtcrime.securesms.util.TextSecurePreferences
|
||||||
import org.whispersystems.signalservice.loki.protocol.multidevice.MultiDeviceProtocol
|
import org.whispersystems.signalservice.loki.protocol.multidevice.MultiDeviceProtocol
|
||||||
import org.whispersystems.signalservice.loki.protocol.todo.LokiThreadFriendRequestStatus
|
|
||||||
|
|
||||||
data class Contact(
|
data class Contact(
|
||||||
val recipient: Recipient,
|
val recipient: Recipient,
|
||||||
val isFriend: Boolean,
|
|
||||||
val isSlave: Boolean,
|
val isSlave: Boolean,
|
||||||
val isOurDevice: Boolean
|
val isOurDevice: Boolean
|
||||||
) {
|
) {
|
||||||
@ -31,10 +29,9 @@ object ContactUtilities {
|
|||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun getAllContacts(context: Context): Set<Contact> {
|
fun getAllContacts(context: Context): Set<Contact> {
|
||||||
val threadDatabase = DatabaseFactory.getThreadDatabase(context)
|
val threadDatabase = DatabaseFactory.getThreadDatabase(context)
|
||||||
val lokiThreadDatabase = DatabaseFactory.getLokiThreadDatabase(context)
|
val userPublicKey = TextSecurePreferences.getLocalNumber(context)
|
||||||
val userHexEncodedPublicKey = TextSecurePreferences.getLocalNumber(context)
|
|
||||||
val lokiAPIDatabase = DatabaseFactory.getLokiAPIDatabase(context)
|
val lokiAPIDatabase = DatabaseFactory.getLokiAPIDatabase(context)
|
||||||
val userDevices = MultiDeviceProtocol.shared.getAllLinkedDevices(userHexEncodedPublicKey)
|
val userDevices = MultiDeviceProtocol.shared.getAllLinkedDevices(userPublicKey)
|
||||||
val cursor = threadDatabase.conversationList
|
val cursor = threadDatabase.conversationList
|
||||||
val result = mutableSetOf<Contact>()
|
val result = mutableSetOf<Contact>()
|
||||||
threadDatabase.readerFor(cursor).use { reader ->
|
threadDatabase.readerFor(cursor).use { reader ->
|
||||||
@ -43,13 +40,12 @@ object ContactUtilities {
|
|||||||
val recipient = thread.recipient
|
val recipient = thread.recipient
|
||||||
val publicKey = recipient.address.serialize()
|
val publicKey = recipient.address.serialize()
|
||||||
val isUserDevice = userDevices.contains(publicKey)
|
val isUserDevice = userDevices.contains(publicKey)
|
||||||
val isFriend = lokiThreadDatabase.getFriendRequestStatus(thread.threadId) == LokiThreadFriendRequestStatus.FRIENDS
|
|
||||||
var isSlave = false
|
var isSlave = false
|
||||||
if (!recipient.isGroupRecipient) {
|
if (!recipient.isGroupRecipient) {
|
||||||
val deviceLinks = lokiAPIDatabase.getDeviceLinks(publicKey)
|
val deviceLinks = lokiAPIDatabase.getDeviceLinks(publicKey)
|
||||||
isSlave = deviceLinks.find { it.slavePublicKey == publicKey } != null
|
isSlave = deviceLinks.find { it.slavePublicKey == publicKey } != null
|
||||||
}
|
}
|
||||||
result.add(Contact(recipient, isFriend, isSlave, isUserDevice))
|
result.add(Contact(recipient, isSlave, isUserDevice))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
|
@ -8,11 +8,11 @@ import org.thoughtcrime.securesms.recipients.Recipient
|
|||||||
fun getOpenGroupDisplayName(recipient: Recipient, threadRecipient: Recipient, context: Context): String {
|
fun getOpenGroupDisplayName(recipient: Recipient, threadRecipient: Recipient, context: Context): String {
|
||||||
val threadID = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(threadRecipient)
|
val threadID = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(threadRecipient)
|
||||||
val publicChat = DatabaseFactory.getLokiThreadDatabase(context).getPublicChat(threadID)
|
val publicChat = DatabaseFactory.getLokiThreadDatabase(context).getPublicChat(threadID)
|
||||||
val hexEncodedPublicKey = recipient.address.toString()
|
val publicKey = recipient.address.toString()
|
||||||
val displayName = if (publicChat != null) {
|
val displayName = if (publicChat != null) {
|
||||||
DatabaseFactory.getLokiUserDatabase(context).getServerDisplayName(publicChat.id, hexEncodedPublicKey)
|
DatabaseFactory.getLokiUserDatabase(context).getServerDisplayName(publicChat.id, publicKey)
|
||||||
} else {
|
} else {
|
||||||
DatabaseFactory.getLokiUserDatabase(context).getDisplayName(hexEncodedPublicKey)
|
DatabaseFactory.getLokiUserDatabase(context).getDisplayName(publicKey)
|
||||||
}
|
}
|
||||||
return displayName ?: hexEncodedPublicKey
|
return displayName ?: publicKey
|
||||||
}
|
}
|
@ -22,7 +22,7 @@ object OpenGroupUtilities {
|
|||||||
val application = ApplicationContext.getInstance(context)
|
val application = ApplicationContext.getInstance(context)
|
||||||
val displayName = TextSecurePreferences.getProfileName(context)
|
val displayName = TextSecurePreferences.getProfileName(context)
|
||||||
val lokiPublicChatAPI = application.publicChatAPI ?: throw Error("LokiPublicChatAPI is not initialized.")
|
val lokiPublicChatAPI = application.publicChatAPI ?: throw Error("LokiPublicChatAPI is not initialized.")
|
||||||
return application.lokiPublicChatManager.addChat(url, channel).then { group ->
|
return application.publicChatManager.addChat(url, channel).then { group ->
|
||||||
DatabaseFactory.getLokiAPIDatabase(context).removeLastMessageServerID(channel, url)
|
DatabaseFactory.getLokiAPIDatabase(context).removeLastMessageServerID(channel, url)
|
||||||
DatabaseFactory.getLokiAPIDatabase(context).removeLastDeletionServerID(channel, url)
|
DatabaseFactory.getLokiAPIDatabase(context).removeLastDeletionServerID(channel, url)
|
||||||
lokiPublicChatAPI.getMessages(channel, url)
|
lokiPublicChatAPI.getMessages(channel, url)
|
||||||
|
@ -50,18 +50,18 @@ class ConversationView : LinearLayout {
|
|||||||
unreadMessagesIndicatorView.visibility = if (thread.unreadCount > 0) View.VISIBLE else View.INVISIBLE
|
unreadMessagesIndicatorView.visibility = if (thread.unreadCount > 0) View.VISIBLE else View.INVISIBLE
|
||||||
if (thread.recipient.isGroupRecipient) {
|
if (thread.recipient.isGroupRecipient) {
|
||||||
if ("Session Public Chat" == thread.recipient.name) {
|
if ("Session Public Chat" == thread.recipient.name) {
|
||||||
profilePictureView.hexEncodedPublicKey = ""
|
profilePictureView.publicKey = ""
|
||||||
profilePictureView.isRSSFeed = true
|
profilePictureView.isRSSFeed = true
|
||||||
} else {
|
} else {
|
||||||
val users = MentionsManager.shared.userPublicKeyCache[thread.threadId]?.toList() ?: listOf()
|
val users = MentionsManager.shared.userPublicKeyCache[thread.threadId]?.toList() ?: listOf()
|
||||||
val randomUsers = users.sorted() // Sort to provide a level of stability
|
val randomUsers = users.sorted() // Sort to provide a level of stability
|
||||||
profilePictureView.hexEncodedPublicKey = randomUsers.getOrNull(0) ?: ""
|
profilePictureView.publicKey = randomUsers.getOrNull(0) ?: ""
|
||||||
profilePictureView.additionalHexEncodedPublicKey = randomUsers.getOrNull(1) ?: ""
|
profilePictureView.additionalPublicKey = randomUsers.getOrNull(1) ?: ""
|
||||||
profilePictureView.isRSSFeed = thread.recipient.name == "Loki News" || thread.recipient.name == "Session Updates"
|
profilePictureView.isRSSFeed = thread.recipient.name == "Loki News" || thread.recipient.name == "Session Updates"
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
profilePictureView.hexEncodedPublicKey = thread.recipient.address.toString()
|
profilePictureView.publicKey = thread.recipient.address.toString()
|
||||||
profilePictureView.additionalHexEncodedPublicKey = null
|
profilePictureView.additionalPublicKey = null
|
||||||
profilePictureView.isRSSFeed = false
|
profilePictureView.isRSSFeed = false
|
||||||
}
|
}
|
||||||
profilePictureView.glide = glide
|
profilePictureView.glide = glide
|
||||||
|
@ -1,190 +0,0 @@
|
|||||||
package org.thoughtcrime.securesms.loki.views
|
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import android.os.Build
|
|
||||||
import android.util.AttributeSet
|
|
||||||
import android.util.TypedValue
|
|
||||||
import android.view.Gravity
|
|
||||||
import android.view.View
|
|
||||||
import android.widget.Button
|
|
||||||
import android.widget.LinearLayout
|
|
||||||
import android.widget.ProgressBar
|
|
||||||
import android.widget.TextView
|
|
||||||
import com.github.ybq.android.spinkit.style.DoubleBounce
|
|
||||||
import network.loki.messenger.R
|
|
||||||
import org.thoughtcrime.securesms.database.DatabaseFactory
|
|
||||||
import org.thoughtcrime.securesms.database.model.MediaMmsMessageRecord
|
|
||||||
import org.thoughtcrime.securesms.database.model.MessageRecord
|
|
||||||
import org.thoughtcrime.securesms.loki.utilities.getColorWithID
|
|
||||||
import org.thoughtcrime.securesms.loki.utilities.toPx
|
|
||||||
import org.whispersystems.signalservice.loki.protocol.todo.LokiMessageFriendRequestStatus
|
|
||||||
|
|
||||||
class FriendRequestView(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : LinearLayout(context, attrs, defStyleAttr) {
|
|
||||||
private var isUISetUp = false
|
|
||||||
private var message: MessageRecord? = null
|
|
||||||
var delegate: FriendRequestViewDelegate? = null
|
|
||||||
|
|
||||||
// region Components
|
|
||||||
private val topSpacer by lazy {
|
|
||||||
val result = View(context)
|
|
||||||
result.layoutParams = LayoutParams(LayoutParams.MATCH_PARENT, toPx(12, resources))
|
|
||||||
result
|
|
||||||
}
|
|
||||||
|
|
||||||
private val label by lazy {
|
|
||||||
val result = TextView(context)
|
|
||||||
result.setTextColor(resources.getColorWithID(R.color.text, context.theme))
|
|
||||||
result.textAlignment = TextView.TEXT_ALIGNMENT_CENTER
|
|
||||||
result.setTextSize(TypedValue.COMPLEX_UNIT_PX, resources.getDimension(R.dimen.small_font_size))
|
|
||||||
result
|
|
||||||
}
|
|
||||||
|
|
||||||
private val buttonLinearLayout by lazy {
|
|
||||||
val result = LinearLayout(context)
|
|
||||||
result.orientation = HORIZONTAL
|
|
||||||
result.setPadding(0, resources.getDimension(R.dimen.medium_spacing).toInt(), 0, 0)
|
|
||||||
result
|
|
||||||
}
|
|
||||||
|
|
||||||
private val loaderContainer by lazy {
|
|
||||||
val result = LinearLayout(context)
|
|
||||||
val layoutParams = LayoutParams(LayoutParams.MATCH_PARENT, toPx(50, resources))
|
|
||||||
result.layoutParams = layoutParams
|
|
||||||
result.gravity = Gravity.CENTER
|
|
||||||
result
|
|
||||||
}
|
|
||||||
// endregion
|
|
||||||
|
|
||||||
// region Initialization
|
|
||||||
constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0)
|
|
||||||
constructor(context: Context) : this(context, null)
|
|
||||||
// endregion
|
|
||||||
|
|
||||||
// region Updating
|
|
||||||
fun update(message: MessageRecord) {
|
|
||||||
this.message = message
|
|
||||||
setUpUIIfNeeded()
|
|
||||||
updateUI()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun setUpUIIfNeeded() {
|
|
||||||
if (isUISetUp) { return }
|
|
||||||
isUISetUp = true
|
|
||||||
orientation = VERTICAL
|
|
||||||
setPadding(toPx(48, resources), 0, toPx(48, resources), 0)
|
|
||||||
addView(topSpacer)
|
|
||||||
addView(label)
|
|
||||||
if (!message!!.isOutgoing) {
|
|
||||||
val loader = ProgressBar(context)
|
|
||||||
loader.isIndeterminate = true
|
|
||||||
loader.indeterminateDrawable = DoubleBounce()
|
|
||||||
val loaderLayoutParams = LayoutParams(LayoutParams.MATCH_PARENT, toPx(24, resources))
|
|
||||||
loader.layoutParams = loaderLayoutParams
|
|
||||||
loaderContainer.addView(loader)
|
|
||||||
addView(loaderContainer)
|
|
||||||
fun button(): Button {
|
|
||||||
val result = Button(context)
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
|
||||||
result.elevation = 0f
|
|
||||||
result.stateListAnimator = null
|
|
||||||
}
|
|
||||||
result.setTextColor(resources.getColorWithID(R.color.text, context.theme))
|
|
||||||
result.setTextSize(TypedValue.COMPLEX_UNIT_PX, resources.getDimension(R.dimen.small_font_size))
|
|
||||||
result.isAllCaps = false
|
|
||||||
result.setPadding(0, 0, 0, 0)
|
|
||||||
val buttonLayoutParams = LayoutParams(0, resources.getDimension(R.dimen.small_button_height).toInt())
|
|
||||||
buttonLayoutParams.weight = 1f
|
|
||||||
result.layoutParams = buttonLayoutParams
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
val rejectButton = button()
|
|
||||||
rejectButton.text = resources.getString(R.string.view_friend_request_reject_button_title)
|
|
||||||
rejectButton.setBackgroundResource(R.drawable.unimportant_dialog_button_background)
|
|
||||||
rejectButton.setOnClickListener { reject() }
|
|
||||||
buttonLinearLayout.addView(rejectButton)
|
|
||||||
val acceptButton = button()
|
|
||||||
acceptButton.text = resources.getString(R.string.view_friend_request_accept_button_title)
|
|
||||||
acceptButton.setBackgroundResource(R.drawable.prominent_dialog_button_background)
|
|
||||||
val acceptButtonLayoutParams = acceptButton.layoutParams as LayoutParams
|
|
||||||
acceptButtonLayoutParams.setMargins(resources.getDimension(R.dimen.medium_spacing).toInt(), 0, 0, 0)
|
|
||||||
acceptButton.layoutParams = acceptButtonLayoutParams
|
|
||||||
acceptButton.setOnClickListener { accept() }
|
|
||||||
buttonLinearLayout.addView(acceptButton)
|
|
||||||
buttonLinearLayout.layoutParams = LayoutParams(LayoutParams.MATCH_PARENT, toPx(50, resources))
|
|
||||||
addView(buttonLinearLayout)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun updateUI() {
|
|
||||||
val message = message
|
|
||||||
val lokiMessageDatabase = DatabaseFactory.getLokiMessageDatabase(context)
|
|
||||||
val contactID = DatabaseFactory.getThreadDatabase(context).getRecipientForThreadId(message!!.threadId)!!.address.toString()
|
|
||||||
val contactDisplayName = DatabaseFactory.getLokiUserDatabase(context).getDisplayName(contactID) ?: contactID
|
|
||||||
val friendRequestStatus = lokiMessageDatabase.getFriendRequestStatus(message.id)
|
|
||||||
if (message is MediaMmsMessageRecord) {
|
|
||||||
visibility = View.GONE
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if (!message.isOutgoing) {
|
|
||||||
visibility = if (friendRequestStatus == LokiMessageFriendRequestStatus.NONE) View.GONE else View.VISIBLE
|
|
||||||
buttonLinearLayout.visibility = if (friendRequestStatus != LokiMessageFriendRequestStatus.REQUEST_PENDING) View.GONE else View.VISIBLE
|
|
||||||
loaderContainer.visibility = if (friendRequestStatus == LokiMessageFriendRequestStatus.REQUEST_SENDING) View.VISIBLE else View.GONE
|
|
||||||
val formatID = when (friendRequestStatus) {
|
|
||||||
LokiMessageFriendRequestStatus.NONE, LokiMessageFriendRequestStatus.REQUEST_SENDING, LokiMessageFriendRequestStatus.REQUEST_FAILED -> return
|
|
||||||
LokiMessageFriendRequestStatus.REQUEST_PENDING -> R.string.view_friend_request_incoming_pending_message
|
|
||||||
LokiMessageFriendRequestStatus.REQUEST_ACCEPTED -> R.string.view_friend_request_incoming_accepted_message
|
|
||||||
LokiMessageFriendRequestStatus.REQUEST_REJECTED -> R.string.view_friend_request_incoming_declined_message
|
|
||||||
LokiMessageFriendRequestStatus.REQUEST_EXPIRED -> R.string.view_friend_request_incoming_expired_message
|
|
||||||
}
|
|
||||||
label.text = resources.getString(formatID, contactDisplayName)
|
|
||||||
} else {
|
|
||||||
visibility = if (friendRequestStatus == LokiMessageFriendRequestStatus.NONE) View.GONE else View.VISIBLE
|
|
||||||
buttonLinearLayout.visibility = View.GONE
|
|
||||||
loaderContainer.visibility = View.GONE
|
|
||||||
val formatID = when (friendRequestStatus) {
|
|
||||||
LokiMessageFriendRequestStatus.NONE -> return
|
|
||||||
LokiMessageFriendRequestStatus.REQUEST_SENDING, LokiMessageFriendRequestStatus.REQUEST_FAILED -> null
|
|
||||||
LokiMessageFriendRequestStatus.REQUEST_PENDING, LokiMessageFriendRequestStatus.REQUEST_REJECTED -> R.string.view_friend_request_outgoing_pending_message
|
|
||||||
LokiMessageFriendRequestStatus.REQUEST_ACCEPTED -> R.string.view_friend_request_outgoing_accepted_message
|
|
||||||
LokiMessageFriendRequestStatus.REQUEST_EXPIRED -> R.string.view_friend_request_outgoing_expired_message
|
|
||||||
}
|
|
||||||
if (formatID != null) {
|
|
||||||
label.text = resources.getString(formatID, contactDisplayName)
|
|
||||||
}
|
|
||||||
label.visibility = if (formatID != null) View.VISIBLE else View.GONE
|
|
||||||
topSpacer.visibility = label.visibility
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// endregion
|
|
||||||
|
|
||||||
// region Interaction
|
|
||||||
private fun accept() {
|
|
||||||
val lokiMessageDatabase = DatabaseFactory.getLokiMessageDatabase(context)
|
|
||||||
lokiMessageDatabase.setFriendRequestStatus(message!!.id, LokiMessageFriendRequestStatus.REQUEST_ACCEPTED)
|
|
||||||
updateUI()
|
|
||||||
delegate?.acceptFriendRequest(message!!)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun reject() {
|
|
||||||
val lokiMessageDatabase = DatabaseFactory.getLokiMessageDatabase(context)
|
|
||||||
lokiMessageDatabase.setFriendRequestStatus(message!!.id, LokiMessageFriendRequestStatus.REQUEST_REJECTED)
|
|
||||||
updateUI()
|
|
||||||
delegate?.rejectFriendRequest(message!!)
|
|
||||||
}
|
|
||||||
// endregion
|
|
||||||
}
|
|
||||||
|
|
||||||
// region Delegate
|
|
||||||
interface FriendRequestViewDelegate {
|
|
||||||
/**
|
|
||||||
* Implementations of this method should update the thread's friend request status
|
|
||||||
* and send a friend request accepted message.
|
|
||||||
*/
|
|
||||||
fun acceptFriendRequest(friendRequest: MessageRecord)
|
|
||||||
/**
|
|
||||||
* Implementations of this method should update the thread's friend request status
|
|
||||||
* and remove the pre keys associated with the contact.
|
|
||||||
*/
|
|
||||||
fun rejectFriendRequest(friendRequest: MessageRecord)
|
|
||||||
}
|
|
||||||
// endregion
|
|
@ -31,8 +31,8 @@ class MentionCandidateView(context: Context, attrs: AttributeSet?, defStyleAttr:
|
|||||||
|
|
||||||
private fun update() {
|
private fun update() {
|
||||||
displayNameTextView.text = mentionCandidate.displayName
|
displayNameTextView.text = mentionCandidate.displayName
|
||||||
profilePictureView.hexEncodedPublicKey = mentionCandidate.publicKey
|
profilePictureView.publicKey = mentionCandidate.publicKey
|
||||||
profilePictureView.additionalHexEncodedPublicKey = null
|
profilePictureView.additionalPublicKey = null
|
||||||
profilePictureView.isRSSFeed = false
|
profilePictureView.isRSSFeed = false
|
||||||
profilePictureView.glide = glide!!
|
profilePictureView.glide = glide!!
|
||||||
profilePictureView.update()
|
profilePictureView.update()
|
||||||
|
@ -21,8 +21,8 @@ import org.thoughtcrime.securesms.util.TextSecurePreferences
|
|||||||
|
|
||||||
class ProfilePictureView : RelativeLayout {
|
class ProfilePictureView : RelativeLayout {
|
||||||
lateinit var glide: GlideRequests
|
lateinit var glide: GlideRequests
|
||||||
var hexEncodedPublicKey: String? = null
|
var publicKey: String? = null
|
||||||
var additionalHexEncodedPublicKey: String? = null
|
var additionalPublicKey: String? = null
|
||||||
var isRSSFeed = false
|
var isRSSFeed = false
|
||||||
var isLarge = false
|
var isLarge = false
|
||||||
|
|
||||||
@ -52,11 +52,11 @@ class ProfilePictureView : RelativeLayout {
|
|||||||
|
|
||||||
// region Updating
|
// region Updating
|
||||||
fun update() {
|
fun update() {
|
||||||
val hexEncodedPublicKey = hexEncodedPublicKey ?: return
|
val publicKey = publicKey ?: return
|
||||||
val additionalHexEncodedPublicKey = additionalHexEncodedPublicKey
|
val additionalPublicKey = additionalPublicKey
|
||||||
doubleModeImageViewContainer.visibility = if (additionalHexEncodedPublicKey != null && !isRSSFeed) View.VISIBLE else View.INVISIBLE
|
doubleModeImageViewContainer.visibility = if (additionalPublicKey != null && !isRSSFeed) View.VISIBLE else View.INVISIBLE
|
||||||
singleModeImageViewContainer.visibility = if (additionalHexEncodedPublicKey == null && !isRSSFeed && !isLarge) View.VISIBLE else View.INVISIBLE
|
singleModeImageViewContainer.visibility = if (additionalPublicKey == null && !isRSSFeed && !isLarge) View.VISIBLE else View.INVISIBLE
|
||||||
largeSingleModeImageViewContainer.visibility = if (additionalHexEncodedPublicKey == null && !isRSSFeed && isLarge) View.VISIBLE else View.INVISIBLE
|
largeSingleModeImageViewContainer.visibility = if (additionalPublicKey == null && !isRSSFeed && isLarge) View.VISIBLE else View.INVISIBLE
|
||||||
rssImageView.visibility = if (isRSSFeed) View.VISIBLE else View.INVISIBLE
|
rssImageView.visibility = if (isRSSFeed) View.VISIBLE else View.INVISIBLE
|
||||||
fun setProfilePictureIfNeeded(imageView: ImageView, hexEncodedPublicKey: String, @DimenRes sizeID: Int) {
|
fun setProfilePictureIfNeeded(imageView: ImageView, hexEncodedPublicKey: String, @DimenRes sizeID: Int) {
|
||||||
glide.clear(imageView)
|
glide.clear(imageView)
|
||||||
@ -76,10 +76,10 @@ class ProfilePictureView : RelativeLayout {
|
|||||||
imageView.setImageDrawable(null)
|
imageView.setImageDrawable(null)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
setProfilePictureIfNeeded(doubleModeImageView1, hexEncodedPublicKey, R.dimen.small_profile_picture_size)
|
setProfilePictureIfNeeded(doubleModeImageView1, publicKey, R.dimen.small_profile_picture_size)
|
||||||
setProfilePictureIfNeeded(doubleModeImageView2, additionalHexEncodedPublicKey ?: "", R.dimen.small_profile_picture_size)
|
setProfilePictureIfNeeded(doubleModeImageView2, additionalPublicKey ?: "", R.dimen.small_profile_picture_size)
|
||||||
setProfilePictureIfNeeded(singleModeImageView, hexEncodedPublicKey, R.dimen.medium_profile_picture_size)
|
setProfilePictureIfNeeded(singleModeImageView, publicKey, R.dimen.medium_profile_picture_size)
|
||||||
setProfilePictureIfNeeded(largeSingleModeImageView, hexEncodedPublicKey, R.dimen.large_profile_picture_size)
|
setProfilePictureIfNeeded(largeSingleModeImageView, publicKey, R.dimen.large_profile_picture_size)
|
||||||
}
|
}
|
||||||
// endregion
|
// endregion
|
||||||
}
|
}
|
@ -48,20 +48,20 @@ class UserView : LinearLayout {
|
|||||||
val address = user.address.serialize()
|
val address = user.address.serialize()
|
||||||
if (user.isGroupRecipient) {
|
if (user.isGroupRecipient) {
|
||||||
if ("Session Public Chat" == user.name || user.address.isRSSFeed) {
|
if ("Session Public Chat" == user.name || user.address.isRSSFeed) {
|
||||||
profilePictureView.hexEncodedPublicKey = ""
|
profilePictureView.publicKey = ""
|
||||||
profilePictureView.additionalHexEncodedPublicKey = null
|
profilePictureView.additionalPublicKey = null
|
||||||
profilePictureView.isRSSFeed = true
|
profilePictureView.isRSSFeed = true
|
||||||
} else {
|
} else {
|
||||||
val threadID = GroupManager.getThreadIDFromGroupID(address, context)
|
val threadID = GroupManager.getThreadIDFromGroupID(address, context)
|
||||||
val users = MentionsManager.shared.userPublicKeyCache[threadID]?.toList() ?: listOf()
|
val users = MentionsManager.shared.userPublicKeyCache[threadID]?.toList() ?: listOf()
|
||||||
val randomUsers = users.sorted() // Sort to provide a level of stability
|
val randomUsers = users.sorted() // Sort to provide a level of stability
|
||||||
profilePictureView.hexEncodedPublicKey = randomUsers.getOrNull(0) ?: ""
|
profilePictureView.publicKey = randomUsers.getOrNull(0) ?: ""
|
||||||
profilePictureView.additionalHexEncodedPublicKey = randomUsers.getOrNull(1) ?: ""
|
profilePictureView.additionalPublicKey = randomUsers.getOrNull(1) ?: ""
|
||||||
profilePictureView.isRSSFeed = false
|
profilePictureView.isRSSFeed = false
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
profilePictureView.hexEncodedPublicKey = address
|
profilePictureView.publicKey = address
|
||||||
profilePictureView.additionalHexEncodedPublicKey = null
|
profilePictureView.additionalPublicKey = null
|
||||||
profilePictureView.isRSSFeed = false
|
profilePictureView.isRSSFeed = false
|
||||||
}
|
}
|
||||||
profilePictureView.glide = glide
|
profilePictureView.glide = glide
|
||||||
|
@ -23,7 +23,6 @@ public class OutgoingMediaMessage {
|
|||||||
private final int distributionType;
|
private final int distributionType;
|
||||||
private final int subscriptionId;
|
private final int subscriptionId;
|
||||||
private final long expiresIn;
|
private final long expiresIn;
|
||||||
public boolean isFriendRequest = false;
|
|
||||||
private final QuoteModel outgoingQuote;
|
private final QuoteModel outgoingQuote;
|
||||||
|
|
||||||
private final List<NetworkFailure> networkFailures = new LinkedList<>();
|
private final List<NetworkFailure> networkFailures = new LinkedList<>();
|
||||||
|
@ -325,7 +325,7 @@ public class DefaultMessageNotifier implements MessageNotifier {
|
|||||||
|
|
||||||
ReplyMethod replyMethod = ReplyMethod.forRecipient(context, recipient);
|
ReplyMethod replyMethod = ReplyMethod.forRecipient(context, recipient);
|
||||||
|
|
||||||
boolean canReply = SessionMetaProtocol.canUserReplyToNotification(recipient, context);
|
boolean canReply = SessionMetaProtocol.canUserReplyToNotification(recipient);
|
||||||
|
|
||||||
PendingIntent quickReplyIntent = canReply ? notificationState.getQuickReplyIntent(context, recipient) : null;
|
PendingIntent quickReplyIntent = canReply ? notificationState.getQuickReplyIntent(context, recipient) : null;
|
||||||
PendingIntent remoteReplyIntent = canReply ? notificationState.getRemoteReplyIntent(context, recipient, replyMethod) : null;
|
PendingIntent remoteReplyIntent = canReply ? notificationState.getRemoteReplyIntent(context, recipient, replyMethod) : null;
|
||||||
|
@ -93,7 +93,7 @@ public class MarkReadReceiver extends BroadcastReceiver {
|
|||||||
for (Address address : addressMap.keySet()) {
|
for (Address address : addressMap.keySet()) {
|
||||||
List<Long> timestamps = Stream.of(addressMap.get(address)).map(SyncMessageId::getTimetamp).toList();
|
List<Long> timestamps = Stream.of(addressMap.get(address)).map(SyncMessageId::getTimetamp).toList();
|
||||||
// Loki - Check whether we want to send a read receipt to this user
|
// Loki - Check whether we want to send a read receipt to this user
|
||||||
if (!SessionMetaProtocol.shouldSendReadReceipt(address, context)) { continue; }
|
if (!SessionMetaProtocol.shouldSendReadReceipt(address)) { continue; }
|
||||||
// Loki - Take into account multi device
|
// Loki - Take into account multi device
|
||||||
Set<String> linkedDevices = MultiDeviceProtocol.shared.getAllLinkedDevices(address.serialize());
|
Set<String> linkedDevices = MultiDeviceProtocol.shared.getAllLinkedDevices(address.serialize());
|
||||||
for (String device : linkedDevices) {
|
for (String device : linkedDevices) {
|
||||||
|
@ -7,7 +7,7 @@ import androidx.annotation.MainThread;
|
|||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.ApplicationContext;
|
import org.thoughtcrime.securesms.ApplicationContext;
|
||||||
import org.thoughtcrime.securesms.loki.api.LokiPublicChatManager;
|
import org.thoughtcrime.securesms.loki.api.PublicChatManager;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||||
import org.thoughtcrime.securesms.util.Debouncer;
|
import org.thoughtcrime.securesms.util.Debouncer;
|
||||||
import org.whispersystems.signalservice.loki.api.Poller;
|
import org.whispersystems.signalservice.loki.api.Poller;
|
||||||
@ -41,14 +41,14 @@ public class OptimizedMessageNotifier implements MessageNotifier {
|
|||||||
@Override
|
@Override
|
||||||
public void updateNotification(@NonNull Context context) {
|
public void updateNotification(@NonNull Context context) {
|
||||||
Poller lokiPoller = ApplicationContext.getInstance(context).lokiPoller;
|
Poller lokiPoller = ApplicationContext.getInstance(context).lokiPoller;
|
||||||
LokiPublicChatManager lokiPublicChatManager = ApplicationContext.getInstance(context).lokiPublicChatManager;
|
PublicChatManager publicChatManager = ApplicationContext.getInstance(context).publicChatManager;
|
||||||
boolean isCaughtUp = true;
|
boolean isCaughtUp = true;
|
||||||
if (lokiPoller != null) {
|
if (lokiPoller != null) {
|
||||||
isCaughtUp = isCaughtUp && lokiPoller.isCaughtUp();
|
isCaughtUp = isCaughtUp && lokiPoller.isCaughtUp();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lokiPublicChatManager != null) {
|
if (publicChatManager != null) {
|
||||||
isCaughtUp = isCaughtUp && lokiPublicChatManager.areAllCaughtUp();
|
isCaughtUp = isCaughtUp && publicChatManager.areAllCaughtUp();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isCaughtUp) {
|
if (isCaughtUp) {
|
||||||
@ -61,14 +61,14 @@ public class OptimizedMessageNotifier implements MessageNotifier {
|
|||||||
@Override
|
@Override
|
||||||
public void updateNotification(@NonNull Context context, long threadId) {
|
public void updateNotification(@NonNull Context context, long threadId) {
|
||||||
Poller lokiPoller = ApplicationContext.getInstance(context).lokiPoller;
|
Poller lokiPoller = ApplicationContext.getInstance(context).lokiPoller;
|
||||||
LokiPublicChatManager lokiPublicChatManager = ApplicationContext.getInstance(context).lokiPublicChatManager;
|
PublicChatManager publicChatManager = ApplicationContext.getInstance(context).publicChatManager;
|
||||||
boolean isCaughtUp = true;
|
boolean isCaughtUp = true;
|
||||||
if (lokiPoller != null) {
|
if (lokiPoller != null) {
|
||||||
isCaughtUp = isCaughtUp && lokiPoller.isCaughtUp();
|
isCaughtUp = isCaughtUp && lokiPoller.isCaughtUp();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lokiPublicChatManager != null) {
|
if (publicChatManager != null) {
|
||||||
isCaughtUp = isCaughtUp && lokiPublicChatManager.areAllCaughtUp();
|
isCaughtUp = isCaughtUp && publicChatManager.areAllCaughtUp();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isCaughtUp) {
|
if (isCaughtUp) {
|
||||||
@ -81,14 +81,14 @@ public class OptimizedMessageNotifier implements MessageNotifier {
|
|||||||
@Override
|
@Override
|
||||||
public void updateNotification(@NonNull Context context, long threadId, boolean signal) {
|
public void updateNotification(@NonNull Context context, long threadId, boolean signal) {
|
||||||
Poller lokiPoller = ApplicationContext.getInstance(context).lokiPoller;
|
Poller lokiPoller = ApplicationContext.getInstance(context).lokiPoller;
|
||||||
LokiPublicChatManager lokiPublicChatManager = ApplicationContext.getInstance(context).lokiPublicChatManager;
|
PublicChatManager publicChatManager = ApplicationContext.getInstance(context).publicChatManager;
|
||||||
boolean isCaughtUp = true;
|
boolean isCaughtUp = true;
|
||||||
if (lokiPoller != null) {
|
if (lokiPoller != null) {
|
||||||
isCaughtUp = isCaughtUp && lokiPoller.isCaughtUp();
|
isCaughtUp = isCaughtUp && lokiPoller.isCaughtUp();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lokiPublicChatManager != null) {
|
if (publicChatManager != null) {
|
||||||
isCaughtUp = isCaughtUp && lokiPublicChatManager.areAllCaughtUp();
|
isCaughtUp = isCaughtUp && publicChatManager.areAllCaughtUp();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isCaughtUp) {
|
if (isCaughtUp) {
|
||||||
@ -101,14 +101,14 @@ public class OptimizedMessageNotifier implements MessageNotifier {
|
|||||||
@Override
|
@Override
|
||||||
public void updateNotification(@android.support.annotation.NonNull Context context, boolean signal, int reminderCount) {
|
public void updateNotification(@android.support.annotation.NonNull Context context, boolean signal, int reminderCount) {
|
||||||
Poller lokiPoller = ApplicationContext.getInstance(context).lokiPoller;
|
Poller lokiPoller = ApplicationContext.getInstance(context).lokiPoller;
|
||||||
LokiPublicChatManager lokiPublicChatManager = ApplicationContext.getInstance(context).lokiPublicChatManager;
|
PublicChatManager publicChatManager = ApplicationContext.getInstance(context).publicChatManager;
|
||||||
boolean isCaughtUp = true;
|
boolean isCaughtUp = true;
|
||||||
if (lokiPoller != null) {
|
if (lokiPoller != null) {
|
||||||
isCaughtUp = isCaughtUp && lokiPoller.isCaughtUp();
|
isCaughtUp = isCaughtUp && lokiPoller.isCaughtUp();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lokiPublicChatManager != null) {
|
if (publicChatManager != null) {
|
||||||
isCaughtUp = isCaughtUp && lokiPublicChatManager.areAllCaughtUp();
|
isCaughtUp = isCaughtUp && publicChatManager.areAllCaughtUp();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isCaughtUp) {
|
if (isCaughtUp) {
|
||||||
|
@ -38,7 +38,6 @@ import org.thoughtcrime.securesms.jobs.MmsSendJob;
|
|||||||
import org.thoughtcrime.securesms.jobs.PushGroupSendJob;
|
import org.thoughtcrime.securesms.jobs.PushGroupSendJob;
|
||||||
import org.thoughtcrime.securesms.jobs.SmsSendJob;
|
import org.thoughtcrime.securesms.jobs.SmsSendJob;
|
||||||
import org.thoughtcrime.securesms.logging.Log;
|
import org.thoughtcrime.securesms.logging.Log;
|
||||||
import org.thoughtcrime.securesms.loki.protocol.FriendRequestProtocol;
|
|
||||||
import org.thoughtcrime.securesms.loki.protocol.MultiDeviceProtocol;
|
import org.thoughtcrime.securesms.loki.protocol.MultiDeviceProtocol;
|
||||||
import org.thoughtcrime.securesms.mms.MmsException;
|
import org.thoughtcrime.securesms.mms.MmsException;
|
||||||
import org.thoughtcrime.securesms.mms.OutgoingMediaMessage;
|
import org.thoughtcrime.securesms.mms.OutgoingMediaMessage;
|
||||||
@ -76,11 +75,6 @@ public class MessageSender {
|
|||||||
|
|
||||||
long messageId = database.insertMessageOutbox(allocatedThreadId, message, forceSms, System.currentTimeMillis(), insertListener);
|
long messageId = database.insertMessageOutbox(allocatedThreadId, message, forceSms, System.currentTimeMillis(), insertListener);
|
||||||
|
|
||||||
// Loki - Set the message's friend request status as soon as it hits the database
|
|
||||||
if (FriendRequestProtocol.shouldUpdateFriendRequestStatusFromOutgoingTextMessage(context, message)) {
|
|
||||||
FriendRequestProtocol.setFriendRequestStatusToSendingIfNeeded(context, messageId, allocatedThreadId);
|
|
||||||
}
|
|
||||||
|
|
||||||
sendTextMessage(context, recipient, forceSms, keyExchange, messageId, message.isEndSession());
|
sendTextMessage(context, recipient, forceSms, keyExchange, messageId, message.isEndSession());
|
||||||
|
|
||||||
return allocatedThreadId;
|
return allocatedThreadId;
|
||||||
@ -107,11 +101,6 @@ public class MessageSender {
|
|||||||
Recipient recipient = message.getRecipient();
|
Recipient recipient = message.getRecipient();
|
||||||
long messageId = database.insertMessageOutbox(message, allocatedThreadId, forceSms, insertListener);
|
long messageId = database.insertMessageOutbox(message, allocatedThreadId, forceSms, insertListener);
|
||||||
|
|
||||||
// Loki - Set the message's friend request status as soon as it hits the database
|
|
||||||
if (FriendRequestProtocol.shouldUpdateFriendRequestStatusFromOutgoingMediaMessage(context, message)) {
|
|
||||||
FriendRequestProtocol.setFriendRequestStatusToSendingIfNeeded(context, messageId, allocatedThreadId);
|
|
||||||
}
|
|
||||||
|
|
||||||
sendMediaMessage(context, recipient, forceSms, messageId, message.getExpiresIn());
|
sendMediaMessage(context, recipient, forceSms, messageId, message.getExpiresIn());
|
||||||
return allocatedThreadId;
|
return allocatedThreadId;
|
||||||
} catch (MmsException e) {
|
} catch (MmsException e) {
|
||||||
|
@ -9,7 +9,6 @@ public class OutgoingTextMessage {
|
|||||||
private final String message;
|
private final String message;
|
||||||
private final int subscriptionId;
|
private final int subscriptionId;
|
||||||
private final long expiresIn;
|
private final long expiresIn;
|
||||||
public boolean isFriendRequest = false;
|
|
||||||
|
|
||||||
public OutgoingTextMessage(Recipient recipient, String message, int subscriptionId) {
|
public OutgoingTextMessage(Recipient recipient, String message, int subscriptionId) {
|
||||||
this(recipient, message, 0, subscriptionId);
|
this(recipient, message, 0, subscriptionId);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user