Remove the concept of friend requests

This commit is contained in:
nielsandriesse 2020-07-15 14:26:20 +10:00
parent 21554441f3
commit 455471b20e
53 changed files with 405 additions and 1332 deletions

View File

@ -45,174 +45,159 @@
</RelativeLayout>
<LinearLayout
android:id="@+id/body_bubble"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_marginEnd="@dimen/massive_spacing"
android:layout_marginStart="12dp"
android:paddingTop="@dimen/medium_spacing"
android:paddingBottom="@dimen/medium_spacing"
android:layout_toStartOf="@+id/indicators_parent"
android:layout_alignWithParentIfMissing="true"
android:orientation="vertical"
android:clipToPadding="false"
android:clipChildren="false">
android:clipChildren="false"
android:background="@color/white"
tools:backgroundTint="@color/conversation_blue">
<LinearLayout
android:id="@+id/body_bubble"
android:id="@+id/group_sender_holder"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/massive_spacing"
android:layout_marginStart="12dp"
android:paddingTop="@dimen/medium_spacing"
android:paddingBottom="@dimen/medium_spacing"
android:orientation="vertical"
android:clipToPadding="false"
android:clipChildren="false"
android:background="@color/white"
tools:backgroundTint="@color/conversation_blue">
android:layout_marginStart="@dimen/message_bubble_horizontal_padding"
android:layout_marginBottom="@dimen/medium_spacing"
android:layout_marginEnd="@dimen/message_bubble_horizontal_padding"
android:orientation="horizontal"
android:visibility="gone"
tools:visibility="visible">
<LinearLayout
android:id="@+id/group_sender_holder"
<TextView
android:id="@+id/group_message_sender"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/message_bubble_horizontal_padding"
android:layout_marginBottom="@dimen/medium_spacing"
android:layout_marginEnd="@dimen/message_bubble_horizontal_padding"
android:orientation="horizontal"
android:visibility="gone"
tools:visibility="visible">
<TextView
android:id="@+id/group_message_sender"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="4sp"
style="@style/Signal.Text.Preview"
android:fontFamily="sans-serif-medium"
android:textColor="?conversation_item_received_text_primary_color"
android:textSize="@dimen/small_font_size"
android:alpha="0.6"
android:maxLines="1"
android:ellipsize="end"
tools:visibility="visible"
tools:text="+14152222222"/>
<TextView
android:id="@+id/group_message_sender_profile"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingStart="4sp"
android:paddingEnd="4sp"
style="@style/Signal.Text.Preview"
android:fontFamily="sans-serif-regular"
android:textColor="?conversation_item_received_text_primary_color"
android:textStyle="italic"
android:maxLines="1"
android:ellipsize="end"
tools:text="~Clement Duval"/>
</LinearLayout>
<org.thoughtcrime.securesms.components.QuoteView
android:id="@+id/quote_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/large_spacing"
android:layout_marginBottom="@dimen/medium_spacing"
android:layout_marginEnd="@dimen/large_spacing"
android:visibility="gone"
app:message_type="incoming"
app:quote_colorPrimary="@color/text"
app:quote_colorSecondary="@color/text"
tools:visibility="visible"/>
<ViewStub
android:id="@+id/shared_contact_view_stub"
android:layout="@layout/conversation_item_received_shared_contact"
android:layout_width="@dimen/media_bubble_default_dimens"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/message_bubble_top_padding"
android:visibility="gone"/>
<ViewStub
android:id="@+id/image_view_stub"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout="@layout/conversation_item_received_thumbnail" />
<ViewStub
android:id="@+id/sticker_view_stub"
android:layout_width="@dimen/media_bubble_sticker_dimens"
android:layout_height="@dimen/media_bubble_sticker_dimens"
android:layout="@layout/conversation_item_received_sticker" />
<ViewStub
android:id="@+id/link_preview_stub"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout="@layout/conversation_item_received_link_preview" />
<ViewStub
android:id="@+id/audio_view_stub"
android:layout="@layout/conversation_item_received_audio"
android:layout_width="210dp"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/message_bubble_horizontal_padding"
android:layout_marginBottom="6dp"
android:layout_marginEnd="@dimen/message_bubble_horizontal_padding" />
<ViewStub
android:id="@+id/document_view_stub"
android:layout="@layout/conversation_item_received_document"
android:layout_width="210dp"
android:layout_height="wrap_content"
android:layout_marginBottom="4dp"
android:layout_marginStart="@dimen/message_bubble_horizontal_padding"
android:layout_marginEnd="@dimen/message_bubble_horizontal_padding" />
<org.thoughtcrime.securesms.components.emoji.EmojiTextView
android:id="@+id/conversation_item_body"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/message_bubble_horizontal_padding"
android:layout_marginEnd="@dimen/message_bubble_horizontal_padding"
style="@style/Signal.Text.Body"
android:layout_marginEnd="4sp"
style="@style/Signal.Text.Preview"
android:fontFamily="sans-serif-medium"
android:textColor="?conversation_item_received_text_primary_color"
android:textColorLink="?conversation_item_received_text_primary_color"
android:ellipsize="end"
app:scaleEmojis="true"
app:emoji_maxLength="1000"
tools:text="Mango pickle lorem ipsum"/>
<org.thoughtcrime.securesms.components.ConversationItemFooter
android:id="@+id/conversation_item_footer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:layout_marginStart="@dimen/message_bubble_horizontal_padding"
android:layout_marginEnd="@dimen/message_bubble_horizontal_padding"
android:clipChildren="false"
android:clipToPadding="false"
android:textSize="@dimen/small_font_size"
android:alpha="0.6"
app:footer_text_color="?conversation_item_received_text_secondary_color"
app:footer_icon_color="?conversation_item_received_text_secondary_color"/>
android:maxLines="1"
android:ellipsize="end"
tools:visibility="visible"
tools:text="+14152222222"/>
<org.thoughtcrime.securesms.components.ConversationItemFooter
android:id="@+id/conversation_item_sticker_footer"
<TextView
android:id="@+id/group_message_sender_profile"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="6dp"
android:layout_marginStart="@dimen/message_bubble_horizontal_padding"
android:layout_marginEnd="@dimen/message_bubble_horizontal_padding"
android:clipChildren="false"
android:clipToPadding="false"
android:visibility="gone"
app:footer_text_color="?conversation_sticker_footer_text_color"
app:footer_icon_color="?conversation_sticker_footer_icon_color"/>
android:paddingStart="4sp"
android:paddingEnd="4sp"
style="@style/Signal.Text.Preview"
android:fontFamily="sans-serif-regular"
android:textColor="?conversation_item_received_text_primary_color"
android:textStyle="italic"
android:maxLines="1"
android:ellipsize="end"
tools:text="~Clement Duval"/>
</LinearLayout>
<org.thoughtcrime.securesms.loki.views.FriendRequestView
android:id="@+id/friend_request_view"
<org.thoughtcrime.securesms.components.QuoteView
android:id="@+id/quote_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/large_spacing"
android:layout_marginBottom="@dimen/medium_spacing"
android:layout_marginEnd="@dimen/large_spacing"
android:visibility="gone"
app:message_type="incoming"
app:quote_colorPrimary="@color/text"
app:quote_colorSecondary="@color/text"
tools:visibility="visible"/>
<ViewStub
android:id="@+id/shared_contact_view_stub"
android:layout="@layout/conversation_item_received_shared_contact"
android:layout_width="@dimen/media_bubble_default_dimens"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/message_bubble_top_padding"
android:visibility="gone"/>
<ViewStub
android:id="@+id/image_view_stub"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout="@layout/conversation_item_received_thumbnail" />
<ViewStub
android:id="@+id/sticker_view_stub"
android:layout_width="@dimen/media_bubble_sticker_dimens"
android:layout_height="@dimen/media_bubble_sticker_dimens"
android:layout="@layout/conversation_item_received_sticker" />
<ViewStub
android:id="@+id/link_preview_stub"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone" />
android:layout="@layout/conversation_item_received_link_preview" />
<ViewStub
android:id="@+id/audio_view_stub"
android:layout="@layout/conversation_item_received_audio"
android:layout_width="210dp"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/message_bubble_horizontal_padding"
android:layout_marginBottom="6dp"
android:layout_marginEnd="@dimen/message_bubble_horizontal_padding" />
<ViewStub
android:id="@+id/document_view_stub"
android:layout="@layout/conversation_item_received_document"
android:layout_width="210dp"
android:layout_height="wrap_content"
android:layout_marginBottom="4dp"
android:layout_marginStart="@dimen/message_bubble_horizontal_padding"
android:layout_marginEnd="@dimen/message_bubble_horizontal_padding" />
<org.thoughtcrime.securesms.components.emoji.EmojiTextView
android:id="@+id/conversation_item_body"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/message_bubble_horizontal_padding"
android:layout_marginEnd="@dimen/message_bubble_horizontal_padding"
style="@style/Signal.Text.Body"
android:textColor="?conversation_item_received_text_primary_color"
android:textColorLink="?conversation_item_received_text_primary_color"
android:ellipsize="end"
app:scaleEmojis="true"
app:emoji_maxLength="1000"
tools:text="Mango pickle lorem ipsum"/>
<org.thoughtcrime.securesms.components.ConversationItemFooter
android:id="@+id/conversation_item_footer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:layout_marginStart="@dimen/message_bubble_horizontal_padding"
android:layout_marginEnd="@dimen/message_bubble_horizontal_padding"
android:clipChildren="false"
android:clipToPadding="false"
android:alpha="0.6"
app:footer_text_color="?conversation_item_received_text_secondary_color"
app:footer_icon_color="?conversation_item_received_text_secondary_color"/>
<org.thoughtcrime.securesms.components.ConversationItemFooter
android:id="@+id/conversation_item_sticker_footer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="6dp"
android:layout_marginStart="@dimen/message_bubble_horizontal_padding"
android:layout_marginEnd="@dimen/message_bubble_horizontal_padding"
android:clipChildren="false"
android:clipToPadding="false"
android:visibility="gone"
app:footer_text_color="?conversation_sticker_footer_text_color"
app:footer_icon_color="?conversation_sticker_footer_icon_color"/>
</LinearLayout>

View File

@ -23,150 +23,135 @@
android:clipChildren="false">
<LinearLayout
android:id="@+id/body_bubble"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_marginStart="@dimen/massive_spacing"
android:paddingTop="@dimen/medium_spacing"
android:paddingBottom="@dimen/medium_spacing"
android:layout_toStartOf="@+id/indicators_parent"
android:layout_alignWithParentIfMissing="true"
android:layout_gravity="end"
android:clipToPadding="false"
android:clipChildren="false">
android:clipChildren="false"
android:background="@color/white"
tools:backgroundTint="@color/core_grey_05">
<LinearLayout
android:id="@+id/body_bubble"
<org.thoughtcrime.securesms.components.QuoteView
android:id="@+id/quote_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_marginStart="@dimen/massive_spacing"
android:paddingTop="@dimen/medium_spacing"
android:paddingBottom="@dimen/medium_spacing"
android:layout_gravity="end"
android:clipToPadding="false"
android:clipChildren="false"
android:background="@color/white"
tools:backgroundTint="@color/core_grey_05">
android:layout_marginStart="@dimen/large_spacing"
android:layout_marginBottom="@dimen/medium_spacing"
android:layout_marginEnd="@dimen/large_spacing"
android:visibility="gone"
app:message_type="outgoing"
app:quote_colorPrimary="@color/text"
app:quote_colorSecondary="@color/text"
tools:visibility="visible"/>
<org.thoughtcrime.securesms.components.QuoteView
android:id="@+id/quote_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/large_spacing"
android:layout_marginBottom="@dimen/medium_spacing"
android:layout_marginEnd="@dimen/large_spacing"
android:visibility="gone"
app:message_type="outgoing"
app:quote_colorPrimary="@color/text"
app:quote_colorSecondary="@color/text"
tools:visibility="visible"/>
<ViewStub
android:id="@+id/shared_contact_view_stub"
android:layout="@layout/conversation_item_sent_shared_contact"
android:layout_width="@dimen/media_bubble_default_dimens"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/medium_spacing"
android:visibility="gone"/>
<ViewStub
android:id="@+id/shared_contact_view_stub"
android:layout="@layout/conversation_item_sent_shared_contact"
android:layout_width="@dimen/media_bubble_default_dimens"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/medium_spacing"
android:visibility="gone"/>
<ViewStub
android:id="@+id/image_view_stub"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout="@layout/conversation_item_sent_thumbnail" />
<ViewStub
android:id="@+id/image_view_stub"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout="@layout/conversation_item_sent_thumbnail" />
<ViewStub
android:id="@+id/sticker_view_stub"
android:layout_width="@dimen/media_bubble_sticker_dimens"
android:layout_height="@dimen/media_bubble_sticker_dimens"
android:layout="@layout/conversation_item_sent_sticker" />
<ViewStub
android:id="@+id/sticker_view_stub"
android:layout_width="@dimen/media_bubble_sticker_dimens"
android:layout_height="@dimen/media_bubble_sticker_dimens"
android:layout="@layout/conversation_item_sent_sticker" />
<ViewStub
android:id="@+id/link_preview_stub"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout="@layout/conversation_item_sent_link_preview" />
<ViewStub
android:id="@+id/audio_view_stub"
android:layout="@layout/conversation_item_sent_audio"
android:layout_width="210dp"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/message_bubble_horizontal_padding"
android:layout_marginBottom="6dp"
android:layout_marginEnd="@dimen/message_bubble_horizontal_padding" />
<ViewStub
android:id="@+id/document_view_stub"
android:layout="@layout/conversation_item_sent_document"
android:layout_width="210dp"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/message_bubble_horizontal_padding"
android:layout_marginBottom="4dp"
android:layout_marginEnd="@dimen/message_bubble_horizontal_padding" />
<org.thoughtcrime.securesms.components.emoji.EmojiTextView
android:id="@+id/conversation_item_body"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/message_bubble_horizontal_padding"
android:layout_marginEnd="@dimen/message_bubble_horizontal_padding"
style="@style/Signal.Text.Body"
android:textColor="?conversation_item_sent_text_primary_color"
android:textColorLink="?conversation_item_sent_text_primary_color"
android:ellipsize="end"
app:scaleEmojis="true"
app:emoji_maxLength="1000"
tools:text="Mango pickle lorem ipsum"/>
<View
android:id="@+id/group_sender_holder"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"/>
<TextView
android:id="@+id/group_message_sender"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone" />
<TextView
android:id="@+id/group_message_sender_profile"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone" />
<org.thoughtcrime.securesms.components.ConversationItemFooter
android:id="@+id/conversation_item_footer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:layout_marginStart="@dimen/message_bubble_horizontal_padding"
android:layout_marginEnd="@dimen/message_bubble_horizontal_padding"
android:clipChildren="false"
android:clipToPadding="false"
app:footer_text_color="?attr/conversation_item_sent_text_secondary_color"
app:footer_icon_color="?attr/conversation_item_sent_icon_color"/>
<org.thoughtcrime.securesms.components.ConversationItemFooter
android:id="@+id/conversation_item_sticker_footer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="6dp"
android:layout_marginStart="@dimen/message_bubble_horizontal_padding"
android:layout_marginEnd="@dimen/message_bubble_horizontal_padding"
android:clipChildren="false"
android:clipToPadding="false"
android:visibility="gone"
app:footer_text_color="?conversation_sticker_footer_text_color"
app:footer_icon_color="?conversation_sticker_footer_icon_color"/>
</LinearLayout>
<org.thoughtcrime.securesms.loki.views.FriendRequestView
android:id="@+id/friend_request_view"
<ViewStub
android:id="@+id/link_preview_stub"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout="@layout/conversation_item_sent_link_preview" />
<ViewStub
android:id="@+id/audio_view_stub"
android:layout="@layout/conversation_item_sent_audio"
android:layout_width="210dp"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/message_bubble_horizontal_padding"
android:layout_marginBottom="6dp"
android:layout_marginEnd="@dimen/message_bubble_horizontal_padding" />
<ViewStub
android:id="@+id/document_view_stub"
android:layout="@layout/conversation_item_sent_document"
android:layout_width="210dp"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/message_bubble_horizontal_padding"
android:layout_marginBottom="4dp"
android:layout_marginEnd="@dimen/message_bubble_horizontal_padding" />
<org.thoughtcrime.securesms.components.emoji.EmojiTextView
android:id="@+id/conversation_item_body"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/message_bubble_horizontal_padding"
android:layout_marginEnd="@dimen/message_bubble_horizontal_padding"
style="@style/Signal.Text.Body"
android:textColor="?conversation_item_sent_text_primary_color"
android:textColorLink="?conversation_item_sent_text_primary_color"
android:ellipsize="end"
app:scaleEmojis="true"
app:emoji_maxLength="1000"
tools:text="Mango pickle lorem ipsum"/>
<View
android:id="@+id/group_sender_holder"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"/>
<TextView
android:id="@+id/group_message_sender"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone" />
<TextView
android:id="@+id/group_message_sender_profile"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone" />
<org.thoughtcrime.securesms.components.ConversationItemFooter
android:id="@+id/conversation_item_footer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:layout_marginStart="@dimen/message_bubble_horizontal_padding"
android:layout_marginEnd="@dimen/message_bubble_horizontal_padding"
android:clipChildren="false"
android:clipToPadding="false"
app:footer_text_color="?attr/conversation_item_sent_text_secondary_color"
app:footer_icon_color="?attr/conversation_item_sent_icon_color"/>
<org.thoughtcrime.securesms.components.ConversationItemFooter
android:id="@+id/conversation_item_sticker_footer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="6dp"
android:layout_marginStart="@dimen/message_bubble_horizontal_padding"
android:layout_marginEnd="@dimen/message_bubble_horizontal_padding"
android:clipChildren="false"
android:clipToPadding="false"
android:visibility="gone"
app:footer_text_color="?conversation_sticker_footer_text_color"
app:footer_icon_color="?conversation_sticker_footer_icon_color"/>
</LinearLayout>
<org.thoughtcrime.securesms.components.AlertView

View File

@ -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_closed_groups_title">Grupy zamknięte</string>
<string name="fragment_contact_selection_open_groups_title">Otwórz grupy</string>
</resources>

View File

@ -1358,6 +1358,7 @@
<!-- Session -->
<string name="continue_2">Продолжить</string>
<string name="copy">Копировать</string>
<string name="invalid_url">Неверная ссылка</string>

View File

@ -1655,7 +1655,6 @@
<!-- Session -->
<string name="continue_2">Continue</string>
<string name="copy">Copy</string>
<string name="invalid_url">Invalid URL</string>

View File

@ -61,13 +61,13 @@ import org.thoughtcrime.securesms.logging.PersistentLogger;
import org.thoughtcrime.securesms.logging.UncaughtExceptionLogger;
import org.thoughtcrime.securesms.loki.activities.HomeActivity;
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.database.LokiAPIDatabase;
import org.thoughtcrime.securesms.loki.database.LokiThreadDatabase;
import org.thoughtcrime.securesms.loki.database.LokiUserDatabase;
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.utilities.Broadcaster;
import org.thoughtcrime.securesms.notifications.DefaultMessageNotifier;
@ -154,7 +154,7 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc
// Loki
public MessageNotifier messageNotifier = null;
public Poller lokiPoller = null;
public LokiPublicChatManager lokiPublicChatManager = null;
public PublicChatManager publicChatManager = null;
private PublicChatAPI publicChatAPI = null;
public Broadcaster broadcaster = null;
public SignalCommunicationModule communicationModule;
@ -184,7 +184,7 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc
LokiThreadDatabase threadDB = DatabaseFactory.getLokiThreadDatabase(this);
LokiUserDatabase userDB = DatabaseFactory.getLokiUserDatabase(this);
String userPublicKey = TextSecurePreferences.getLocalNumber(this);
LokiSessionResetImplementation sessionResetImpl = new LokiSessionResetImplementation(this);
SessionResetImplementation sessionResetImpl = new SessionResetImplementation(this);
if (userPublicKey != null) {
SwarmAPI.Companion.configureIfNeeded(apiDB);
SnodeAPI.Companion.configureIfNeeded(userPublicKey, apiDB, broadcaster);
@ -203,7 +203,7 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc
}
}
resubmitProfilePictureIfNeeded();
lokiPublicChatManager = new LokiPublicChatManager(this);
publicChatManager = new PublicChatManager(this);
updateOpenGroupProfilePicturesIfNeeded();
registerForFCMIfNeeded(false);
// ========
@ -229,8 +229,8 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc
// Loki
if (lokiPoller != null) { lokiPoller.setCaughtUp(false); }
startPollingIfNeeded();
lokiPublicChatManager.markAllAsNotCaughtUp();
lokiPublicChatManager.startPollersIfNeeded();
publicChatManager.markAllAsNotCaughtUp();
publicChatManager.startPollersIfNeeded();
}
@Override
@ -241,7 +241,7 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc
messageNotifier.setVisibleThread(-1);
// Loki
if (lokiPoller != null) { lokiPoller.stopIfNeeded(); }
if (lokiPublicChatManager != null) { lokiPublicChatManager.stopPollers(); }
if (publicChatManager != null) { publicChatManager.stopPollers(); }
}
@Override

View File

@ -322,7 +322,7 @@ public class GroupCreateActivity extends PassphraseRequiredActionBarActivity
@Override
public void onClick(View v) {
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);
}
}

View File

@ -53,7 +53,7 @@ public class InviteActivity extends PassphraseRequiredActionBarActivity {
@Override
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.REFRESHABLE, false);

View File

@ -84,7 +84,7 @@ public class TypingStatusSender {
ThreadDatabase threadDatabase = DatabaseFactory.getThreadDatabase(context);
Recipient recipient = threadDatabase.getRecipientForThreadId(threadId);
// 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
Set<String> linkedDevices = MultiDeviceProtocol.shared.getAllLinkedDevices(recipient.getAddress().serialize());
for (String device : linkedDevices) {

View File

@ -68,7 +68,6 @@ import android.view.View.OnFocusChangeListener;
import android.view.View.OnKeyListener;
import android.view.WindowManager;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.ImageView;
@ -81,7 +80,6 @@ import com.annimon.stream.Stream;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
import org.jetbrains.annotations.NotNull;
import org.thoughtcrime.securesms.ApplicationContext;
import org.thoughtcrime.securesms.ExpirationDialog;
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.LokiUserDatabase;
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.utilities.MentionManagerUtilities;
import org.thoughtcrime.securesms.loki.views.FriendRequestViewDelegate;
import org.thoughtcrime.securesms.loki.views.MentionCandidateSelectionView;
import org.thoughtcrime.securesms.loki.views.SessionRestoreBannerView;
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.meta.SessionMetaProtocol;
import org.whispersystems.signalservice.loki.protocol.multidevice.MultiDeviceProtocol;
import org.whispersystems.signalservice.loki.protocol.todo.LokiThreadFriendRequestStatus;
import org.whispersystems.signalservice.loki.utilities.PublicKeyValidation;
import java.io.IOException;
@ -272,8 +267,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
ComposeText.CursorPositionChangedListener,
ConversationSearchBottomBar.EventListener,
StickerKeyboardProvider.StickerEventListener,
LokiThreadDatabaseDelegate,
FriendRequestViewDelegate
LokiThreadDatabaseDelegate
{
private static final String TAG = ConversationActivity.class.getSimpleName();
@ -355,14 +349,14 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
// Message status bar
private ArrayList<BroadcastReceiver> broadcastReceivers = new ArrayList<>();
private String messageStatus = null;
private String messageStatus = null;
// Mentions
private View mentionCandidateSelectionViewContainer;
private View mentionCandidateSelectionViewContainer;
private MentionCandidateSelectionView mentionCandidateSelectionView;
private int currentMentionStartIndex = -1;
private ArrayList<Mention> mentions = new ArrayList<>();
private String oldText = "";
private int currentMentionStartIndex = -1;
private ArrayList<Mention> mentions = new ArrayList<>();
private String oldText = "";
// Restoration
protected SessionRestoreBannerView sessionRestoreBannerView;
@ -386,7 +380,6 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
getWindow().getDecorView().setBackgroundColor(color);
fragment = initFragment(R.id.fragment_content, new ConversationFragment(), dynamicLanguage.getCurrentLocale());
fragment.friendRequestViewDelegate = this;
registerMessageStatusObserver("calculatingPoW");
registerMessageStatusObserver("contactingNetwork");
@ -554,8 +547,6 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
DatabaseFactory.getLokiThreadDatabase(this).setDelegate(this);
updateInputPanel();
updateSessionRestoreBanner();
Log.i(TAG, "onResume() Finished: " + (System.currentTimeMillis() - getIntent().getLongExtra(TIMING_EXTRA, 0)));
@ -2252,26 +2243,6 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
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
public void handleSessionRestoreDevicesChanged(long 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() {
if (inputPanel.isRecordingInLockedMode()) {
inputPanel.releaseRecordingLock();
@ -2395,11 +2351,6 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
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) {
inputPanel.clearQuote();
attachmentManager.clear(glideRequests, false);
@ -2448,11 +2399,6 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
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("");
final long id = fragment.stageOutgoingMessage(message);
@ -2482,13 +2428,6 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
}
private void updateToggleButtonState() {
if (!FriendRequestProtocol.shouldAttachmentButtonBeEnabled(this, recipient)) {
buttonToggle.display(sendButton);
quickAttachmentToggle.hide();
inlineAttachmentToggle.hide();
return;
}
if (inputPanel.isRecordingInLockedMode()) {
buttonToggle.display(sendButton);
quickAttachmentToggle.show();
@ -3192,19 +3131,5 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
updateSubtitleTextView();
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
}

View File

@ -40,7 +40,6 @@ import org.thoughtcrime.securesms.database.MmsSmsDatabase;
import org.thoughtcrime.securesms.database.model.MessageRecord;
import org.thoughtcrime.securesms.database.model.MmsMessageRecord;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.loki.views.FriendRequestViewDelegate;
import org.thoughtcrime.securesms.mms.GlideRequests;
import org.thoughtcrime.securesms.mms.SlideDeck;
import org.thoughtcrime.securesms.recipients.Recipient;
@ -108,8 +107,6 @@ public class ConversationAdapter <V extends View & BindableConversationItem>
private MessageRecord recordToPulseHighlight;
private String searchQuery;
public FriendRequestViewDelegate friendRequestViewDelegate; // Loki
protected static class ViewHolder extends RecyclerView.ViewHolder {
public <V extends View & BindableConversationItem> ViewHolder(final @NonNull V 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 nextRecord = adapterPosition > 0 && !isHeaderPosition(adapterPosition - 1) ? getRecordForPositionOrThrow(adapterPosition - 1) : null;
BindableConversationItem conversationItem = viewHolder.getView();
if (conversationItem instanceof ConversationItem) {
((ConversationItem)conversationItem).friendRequestViewDelegate = this.friendRequestViewDelegate;
}
conversationItem.bind(messageRecord,
viewHolder.getView().bind(messageRecord,
Optional.fromNullable(previousRecord),
Optional.fromNullable(nextRecord),
glideRequests,

View File

@ -79,7 +79,6 @@ import org.thoughtcrime.securesms.database.model.MessageRecord;
import org.thoughtcrime.securesms.database.model.MmsMessageRecord;
import org.thoughtcrime.securesms.linkpreview.LinkPreview;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.loki.views.FriendRequestViewDelegate;
import org.thoughtcrime.securesms.longmessage.LongMessageActivity;
import org.thoughtcrime.securesms.mediasend.Media;
import org.thoughtcrime.securesms.mms.GlideApp;
@ -151,7 +150,6 @@ public class ConversationFragment extends Fragment
private View composeDivider;
private View scrollToBottomButton;
private TextView scrollDateHeader;
public FriendRequestViewDelegate friendRequestViewDelegate; // Loki
@Override
public void onCreate(Bundle icicle) {
@ -706,7 +704,6 @@ public class ConversationFragment extends Fragment
if (adapter == null) {
return;
}
adapter.friendRequestViewDelegate = this.friendRequestViewDelegate;
if (cursor.getCount() >= PARTIAL_CONVERSATION_LIMIT && loader.hasLimit()) {
adapter.setFooterView(topLoadMoreView);

View File

@ -86,10 +86,7 @@ import org.thoughtcrime.securesms.jobs.SmsSendJob;
import org.thoughtcrime.securesms.linkpreview.LinkPreview;
import org.thoughtcrime.securesms.linkpreview.LinkPreviewUtil;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.loki.database.LokiMessageDatabase;
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.mms.GlideRequests;
import org.thoughtcrime.securesms.mms.ImageSlide;
@ -158,7 +155,6 @@ public class ConversationItem extends LinearLayout
private ViewGroup contactPhotoHolder;
private AlertView alertView;
private ViewGroup container;
private FriendRequestView friendRequestView;
private @NonNull Set<MessageRecord> batchSelected = new HashSet<>();
private Recipient conversationRecipient;
@ -182,8 +178,6 @@ public class ConversationItem extends LinearLayout
private final Context context;
public FriendRequestViewDelegate friendRequestViewDelegate; // Loki
public ConversationItem(Context context) {
this(context, null);
}
@ -223,7 +217,6 @@ public class ConversationItem extends LinearLayout
this.groupSenderHolder = findViewById(R.id.group_sender_holder);
this.quoteView = findViewById(R.id.quote_view);
this.container = findViewById(R.id.container);
this.friendRequestView = findViewById(R.id.friend_request_view);
setOnClickListener(new ClickListener(null));
@ -269,7 +262,6 @@ public class ConversationItem extends LinearLayout
setQuote(messageRecord, previousMessageRecord, nextMessageRecord, groupThread);
setMessageSpacing(context, messageRecord, previousMessageRecord, nextMessageRecord, groupThread);
setFooter(messageRecord, nextMessageRecord, locale, groupThread);
setFriendRequestView(messageRecord);
adjustMarginsIfNeeded(messageRecord);
}
@ -807,8 +799,8 @@ public class ConversationItem extends LinearLayout
layoutParams.setMarginStart((groupThread && !isRSSFeed) ? groupThreadMargin : defaultMargin);
bodyBubble.setLayoutParams(layoutParams);
if (profilePictureView == null) return;
profilePictureView.setHexEncodedPublicKey(recipient.getAddress().toString());
profilePictureView.setAdditionalHexEncodedPublicKey(null);
profilePictureView.setPublicKey(recipient.getAddress().toString());
profilePictureView.setAdditionalPublicKey(null);
profilePictureView.setRSSFeed(false);
profilePictureView.setGlide(glideRequests);
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) {
if (hasSticker(messageRecord)) {
return stickerFooter;
@ -1067,10 +1054,8 @@ public class ConversationItem extends LinearLayout
int spacingBottom = spacingTop;
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);
}

View File

@ -885,7 +885,7 @@ public class SmsDatabase extends MessagingDatabase {
0, message.isSecureMessage() ? MmsSmsColumns.Types.getOutgoingEncryptedMessageType() : MmsSmsColumns.Types.getOutgoingSmsMessageType(),
threadId, 0, new LinkedList<IdentityKeyMismatch>(),
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);
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,
recipient,
addressDeviceId,
dateSent, dateReceived, deliveryReceiptCount, type,
threadId, status, mismatches, subscriptionId,
expiresIn, expireStarted, readReceiptCount, unidentified, isFriendRequest);
expiresIn, expireStarted, readReceiptCount, unidentified);
}
private List<IdentityKeyMismatch> getMismatches(String document) {

View File

@ -145,10 +145,9 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper {
db.execSQL(LokiAPIDatabase.getCreateSessionRequestTimestampCacheCommand());
db.execSQL(LokiPreKeyBundleDatabase.getCreateTableCommand());
db.execSQL(LokiPreKeyRecordDatabase.getCreateTableCommand());
db.execSQL(LokiMessageDatabase.getCreateMessageFriendRequestTableCommand());
db.execSQL(LokiMessageDatabase.getCreateMessageIDTableCommand());
db.execSQL(LokiMessageDatabase.getCreateMessageToThreadMappingTableCommand());
db.execSQL(LokiMessageDatabase.getCreateErrorMessageTableCommand());
db.execSQL(LokiThreadDatabase.getCreateFriendRequestTableCommand());
db.execSQL(LokiThreadDatabase.getCreateSessionResetTableCommand());
db.execSQL(LokiThreadDatabase.getCreatePublicChatTableCommand());
db.execSQL(LokiUserDatabase.getCreateDisplayNameTableCommand());

View File

@ -39,23 +39,6 @@ import network.loki.messenger.R;
*/
public class SmsMessageRecord extends MessageRecord {
// Loki
private final boolean isFriendRequest;
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)
{
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,
@ -65,22 +48,18 @@ public class SmsMessageRecord extends MessageRecord {
long type, long threadId,
int status, List<IdentityKeyMismatch> mismatches,
int subscriptionId, long expiresIn, long expireStarted,
int readReceiptCount, boolean unidentified, boolean isFriendRequest)
int readReceiptCount, boolean unidentified)
{
super(id, body, recipient, individualRecipient, recipientDeviceId,
dateSent, dateReceived, threadId, status, deliveryReceiptCount, type,
mismatches, new LinkedList<>(), subscriptionId,
expiresIn, expireStarted, readReceiptCount, unidentified);
this.isFriendRequest = isFriendRequest;
}
public long getType() {
return type;
}
// Loki
public boolean isFriendRequest() { return isFriendRequest; }
@Override
public SpannableString getDisplayBody(@NonNull Context context) {
Recipient recipient = getRecipient();

View File

@ -45,7 +45,7 @@ import org.thoughtcrime.securesms.jobs.StickerPackDownloadJob;
import org.thoughtcrime.securesms.jobs.TypingSendJob;
import org.thoughtcrime.securesms.linkpreview.LinkPreviewRepository;
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.preferences.AppProtectionPreferenceFragment;
import org.thoughtcrime.securesms.push.MessageSenderEventListener;
@ -156,7 +156,7 @@ public class SignalCommunicationModule {
DatabaseFactory.getLokiThreadDatabase(context),
DatabaseFactory.getLokiMessageDatabase(context),
DatabaseFactory.getLokiPreKeyBundleDatabase(context),
new LokiSessionResetImplementation(context),
new SessionResetImplementation(context),
DatabaseFactory.getLokiUserDatabase(context),
((ApplicationContext)context.getApplicationContext()).broadcaster);
} else {

View File

@ -139,7 +139,6 @@ public class MultiDeviceContactUpdateJob extends BaseJob implements InjectableTy
Optional<IdentityDatabase.IdentityRecord> identityRecord = DatabaseFactory.getIdentityDatabase(context).getIdentity(address);
Optional<VerifiedMessage> verifiedMessage = getVerifiedMessage(recipient, identityRecord);
// Loki - Only sync contacts we are friends with
if (SyncMessagesProtocol.shouldSyncContact(context, address)) {
out.write(new DeviceContact(address.toPhoneString(),
Optional.fromNullable(recipient.getName()),

View File

@ -66,15 +66,11 @@ import org.thoughtcrime.securesms.linkpreview.LinkPreviewUtil;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.loki.activities.HomeActivity;
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.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.PushEphemeralMessageSendJob;
import org.thoughtcrime.securesms.loki.protocol.SessionManagementProtocol;
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.utilities.MentionManagerUtilities;
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.crypto.LokiServiceCipher;
import org.whispersystems.signalservice.loki.protocol.mentions.MentionsManager;
import org.whispersystems.signalservice.loki.protocol.todo.LokiThreadFriendRequestStatus;
import org.whispersystems.signalservice.loki.utilities.PublicKeyValidation;
import java.security.MessageDigest;
@ -145,8 +140,6 @@ import javax.inject.Inject;
import network.loki.messenger.R;
import static org.thoughtcrime.securesms.loki.utilities.RecipientUtilitiesKt.recipient;
public class PushDecryptJob extends BaseJob implements InjectableType {
public static final String KEY = "PushDecryptJob";
@ -225,9 +218,7 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
}
@Override
public void onCanceled() {
}
public void onCanceled() { }
public void processMessage(@NonNull SignalServiceEnvelope envelope, boolean isPushNotification) {
synchronized (PushReceivedJob.RECEIVE_LOCK) {
@ -264,18 +255,12 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
try {
GroupDatabase groupDatabase = DatabaseFactory.getGroupDatabase(context);
SignalProtocolStore axolotlStore = new SignalProtocolStoreImpl(context);
SessionResetProtocol sessionResetProtocol = new LokiSessionResetImplementation(context);
SessionResetProtocol sessionResetProtocol = new SessionResetImplementation(context);
SignalServiceAddress localAddress = new SignalServiceAddress(TextSecurePreferences.getLocalNumber(context));
LokiServiceCipher cipher = new LokiServiceCipher(localAddress, axolotlStore, sessionResetProtocol, UnidentifiedAccessUtil.getCertificateValidator());
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)) {
Log.i(TAG, "Ignoring message.");
return;
@ -300,8 +285,6 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
if (message.isDeviceUnlinkingRequest()) {
MultiDeviceProtocol.handleUnlinkingRequestIfNeeded(context, content);
} else {
// Loki - Handle friend request acceptance if needed
FriendRequestProtocol.handleFriendRequestAcceptanceIfNeeded(context, content.getSender(), content);
if (message.isEndSession()) {
handleEndSessionMessage(content, smsMessageId);
@ -311,14 +294,8 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
handleExpirationUpdate(content, message, smsMessageId);
} else if (isMediaMessage) {
handleMediaMessage(content, message, smsMessageId, Optional.absent());
// Loki - Handle friend request message if needed
FriendRequestProtocol.handleFriendRequestMessageIfNeeded(context, content.getSender(), content);
} else if (message.getBody().isPresent()) {
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()))) {
@ -364,7 +341,6 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
} else if (content.getTypingMessage().isPresent()) {
handleTypingMessage(content, content.getTypingMessage().get());
} else if (content.getNullMessage().isPresent()) {
// Loki - This is needed for compatibility with refactored desktop clients
// ========
// if (content.isFriendRequest()) {
@ -372,18 +348,6 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
// } else {
// 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()));
}
// ========
}

View File

@ -2,7 +2,6 @@ package org.thoughtcrime.securesms.jobs;
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.WorkerThread;
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.UndeliverableMessageException;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.whispersystems.libsignal.state.PreKeyBundle;
import org.whispersystems.libsignal.util.guava.Optional;
import org.whispersystems.signalservice.api.SignalServiceMessageSender;
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_MESSAGE_ID = "message_id";
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;
private long messageId; // The message ID
private long templateMessageId; // The message ID of the message to template this send job from
// 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
private long messageId;
private long templateMessageId;
private Address destination;
public PushMediaSendJob(long messageId, Address destination) {
this(messageId, messageId, 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) {
this(constructParameters(destination), templateMessageId, messageId, destination, isLokiPreKeyBundleMessage, customFriendRequestMessage);
}
private PushMediaSendJob(@NonNull Job.Parameters parameters, long templateMessageId, long messageId, Address destination, boolean isLokiPreKeyBundleMessage, String customFriendRequestMessage) {
private PushMediaSendJob(@NonNull Job.Parameters parameters, long templateMessageId, long messageId, Address destination) {
super(parameters);
this.templateMessageId = templateMessageId;
this.messageId = messageId;
this.destination = destination;
this.isLokiPreKeyBundleMessage = isLokiPreKeyBundleMessage;
this.customFriendRequestMessage = customFriendRequestMessage;
}
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) {
enqueue(context, jobManager, Collections.singletonList(new PushMediaSendJob(templateMessageId, messageId, destination, isFriendRequest, 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)));
}
@WorkerThread
@ -144,14 +130,10 @@ public class PushMediaSendJob extends PushSendJob implements InjectableType {
@Override
public @NonNull Data serialize() {
Data.Builder builder = new Data.Builder()
.putLong(KEY_TEMPLATE_MESSAGE_ID, templateMessageId)
.putLong(KEY_MESSAGE_ID, messageId)
.putString(KEY_DESTINATION, destination.serialize())
.putBoolean(KEY_IS_LOKI_PRE_KEY_BUNDLE_MESSAGE, isLokiPreKeyBundleMessage);
if (customFriendRequestMessage != null) { builder.putString(KEY_CUSTOM_FR_MESSAGE, customFriendRequestMessage); }
return builder.build();
return new Data.Builder()
.putLong(KEY_TEMPLATE_MESSAGE_ID, templateMessageId)
.putLong(KEY_MESSAGE_ID, messageId)
.putString(KEY_DESTINATION, destination.serialize()).build();
}
@Override
@ -270,17 +252,8 @@ public class PushMediaSendJob extends PushSendJob implements InjectableType {
List<SharedContact> sharedContacts = getSharedContactsFor(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()
.withBody(body)
.withBody(message.getBody())
.withAttachments(serviceAttachments)
.withTimestamp(message.getSentTimeMillis())
.withExpiration((int)(message.getExpiresIn() / 1000))
@ -290,7 +263,6 @@ public class PushMediaSendJob extends PushSendJob implements InjectableType {
.withSharedContacts(sharedContacts)
.withPreviews(previews)
.asExpirationUpdate(message.isExpirationUpdate())
.withPreKeyBundle(preKeyBundle)
.build();
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 messageID = data.getLong(KEY_MESSAGE_ID);
Address destination = Address.fromSerialized(data.getString(KEY_DESTINATION));
boolean isLokiPreKeyBundleMessage = data.getBoolean(KEY_IS_LOKI_PRE_KEY_BUNDLE_MESSAGE);
String customFRMessage = data.hasString(KEY_CUSTOM_FR_MESSAGE) ? data.getString(KEY_CUSTOM_FR_MESSAGE) : null;
return new PushMediaSendJob(parameters, templateMessageID, messageID, destination, isLokiPreKeyBundleMessage, customFRMessage);
return new PushMediaSendJob(parameters, templateMessageID, messageID, destination);
}
}
}

View File

@ -21,7 +21,6 @@ import org.thoughtcrime.securesms.service.ExpiringMessageManager;
import org.thoughtcrime.securesms.transport.InsecureFallbackApprovalException;
import org.thoughtcrime.securesms.transport.RetryLaterException;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.whispersystems.libsignal.state.PreKeyBundle;
import org.whispersystems.libsignal.util.guava.Optional;
import org.whispersystems.signalservice.api.SignalServiceMessageSender;
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_MESSAGE_ID = "message_id";
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;
private long messageId; // The message ID
private long templateMessageId; // The message ID of the message to template this send job from
// 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
private long messageId;
private long templateMessageId;
private Address destination;
public PushTextSendJob(long messageId, Address destination) {
this(messageId, messageId, 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) {
this(constructParameters(destination), templateMessageId, messageId, destination, isLokiPreKeyBundleMessage, customFriendRequestMessage);
}
private PushTextSendJob(@NonNull Job.Parameters parameters, long templateMessageId, long messageId, Address destination, boolean isLokiPreKeyBundleMessage, String customFriendRequestMessage) {
private PushTextSendJob(@NonNull Job.Parameters parameters, long templateMessageId, long messageId, Address destination) {
super(parameters);
this.templateMessageId = templateMessageId;
this.messageId = messageId;
this.destination = destination;
this.isLokiPreKeyBundleMessage = isLokiPreKeyBundleMessage;
this.customFriendRequestMessage = customFriendRequestMessage;
}
@Override
public @NonNull Data serialize() {
Data.Builder builder = new Data.Builder()
.putLong(KEY_TEMPLATE_MESSAGE_ID, templateMessageId)
.putLong(KEY_MESSAGE_ID, messageId)
.putString(KEY_DESTINATION, destination.serialize())
.putBoolean(KEY_IS_LOKI_PRE_KEY_BUNDLE_MESSAGE, isLokiPreKeyBundleMessage);
if (customFriendRequestMessage != null) { builder.putString(KEY_CUSTOM_FR_MESSAGE, customFriendRequestMessage); }
return builder.build();
return new Data.Builder()
.putLong(KEY_TEMPLATE_MESSAGE_ID, templateMessageId)
.putLong(KEY_MESSAGE_ID, messageId)
.putString(KEY_DESTINATION, destination.serialize()).build();
}
@Override
@ -213,22 +196,12 @@ public class PushTextSendJob extends PushSendJob implements InjectableType {
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()
.withTimestamp(message.getDateSent())
.withBody(body)
.withBody(message.getBody())
.withExpiration((int)(message.getExpiresIn() / 1000))
.withProfileKey(profileKey.orNull())
.asEndSessionMessage(message.isEndSession())
.withPreKeyBundle(preKeyBundle)
.build();
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 messageID = data.getLong(KEY_MESSAGE_ID);
Address destination = Address.fromSerialized(data.getString(KEY_DESTINATION));
boolean isLokiPreKeyBundleMessage = data.getBoolean(KEY_IS_LOKI_PRE_KEY_BUNDLE_MESSAGE);
String customFRMessage = data.hasString(KEY_CUSTOM_FR_MESSAGE) ? data.getString(KEY_CUSTOM_FR_MESSAGE) : null;
return new PushTextSendJob(parameters, templateMessageID, messageID, destination, isLokiPreKeyBundleMessage, customFRMessage);
return new PushTextSendJob(parameters, templateMessageID, messageID, destination);
}
}
}

View File

@ -8,9 +8,8 @@ class CreateClosedGroupLoader(context: Context) : AsyncLoader<List<String>>(cont
override fun loadInBackground(): List<String> {
val contacts = ContactUtilities.getAllContacts(context)
// Only show the master devices of the users we are friends with
return contacts.filter { contact ->
!contact.recipient.isGroupRecipient && contact.isFriend && !contact.isOurDevice && !contact.isSlave
!contact.recipient.isGroupRecipient && !contact.isOurDevice && !contact.isSlave
}.map {
it.recipient.address.toPhoneString()
}

View File

@ -33,7 +33,7 @@ import org.thoughtcrime.securesms.database.ThreadDatabase
import org.thoughtcrime.securesms.database.model.ThreadRecord
import org.thoughtcrime.securesms.loki.dialogs.PNModeBottomSheet
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.views.ConversationView
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.sessionmanagement.SessionManagementProtocol
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
class HomeActivity : PassphraseRequiredActionBarActivity, ConversationClickListener, SeedReminderViewDelegate, NewConversationButtonSetViewDelegate {
private lateinit var glide: GlideRequests
private val hexEncodedPublicKey: String
private val publicKey: String
get() {
val masterHexEncodedPublicKey = TextSecurePreferences.getMasterHexEncodedPublicKey(this)
val userHexEncodedPublicKey = TextSecurePreferences.getLocalNumber(this)
return masterHexEncodedPublicKey ?: userHexEncodedPublicKey
val masterPublicKey = TextSecurePreferences.getMasterHexEncodedPublicKey(this)
val userPublicKey = TextSecurePreferences.getLocalNumber(this)
return masterPublicKey ?: userPublicKey
}
// region Lifecycle
@ -94,7 +92,7 @@ class HomeActivity : PassphraseRequiredActionBarActivity, ConversationClickListe
glide = GlideApp.with(this)
// Set up toolbar buttons
profileButton.glide = glide
profileButton.hexEncodedPublicKey = hexEncodedPublicKey
profileButton.publicKey = publicKey
profileButton.update()
profileButton.setOnClickListener { openSettings() }
pathStatusViewContainer.setOnClickListener { showPath() }
@ -156,45 +154,23 @@ class HomeActivity : PassphraseRequiredActionBarActivity, ConversationClickListe
val threadDB = DatabaseFactory.getLokiThreadDatabase(this)
val userDB = DatabaseFactory.getLokiUserDatabase(this)
val userPublicKey = TextSecurePreferences.getLocalNumber(this)
val sessionResetImpl = LokiSessionResetImplementation(this)
val sessionResetImpl = SessionResetImplementation(this)
if (userPublicKey != null) {
MentionsManager.configureIfNeeded(userPublicKey, threadDB, userDB)
SessionMetaProtocol.configureIfNeeded(apiDB, userPublicKey)
SyncMessagesProtocol.configureIfNeeded(apiDB, userPublicKey)
application.lokiPublicChatManager.startPollersIfNeeded()
application.publicChatManager.startPollersIfNeeded()
}
SessionManagementProtocol.configureIfNeeded(sessionResetImpl, threadDB, application)
MultiDeviceProtocol.configureIfNeeded(apiDB)
IP2Country.configureIfNeeded(this)
// Preload device links to make message sending quicker
val publicKeys = ContactUtilities.getAllContacts(this).filter { contact ->
!contact.recipient.isGroupRecipient && contact.isFriend && !contact.isOurDevice && !contact.isSlave
!contact.recipient.isGroupRecipient && !contact.isOurDevice && !contact.isSlave
}.map {
it.recipient.address.toPhoneString()
}.toSet()
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() {

View File

@ -15,7 +15,7 @@ import org.thoughtcrime.securesms.database.IdentityDatabase
import org.thoughtcrime.securesms.logging.Log
import org.thoughtcrime.securesms.loki.dialogs.LinkDeviceSlaveModeDialog
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.utilities.push
import org.thoughtcrime.securesms.loki.utilities.setUpActionBarSessionLogo
@ -109,7 +109,7 @@ class LandingActivity : BaseActionBarActivity(), LinkDeviceSlaveModeDialogDelega
val threadDB = DatabaseFactory.getLokiThreadDatabase(this)
val userDB = DatabaseFactory.getLokiUserDatabase(this)
val userPublicKey = TextSecurePreferences.getLocalNumber(this)
val sessionResetImpl = LokiSessionResetImplementation(this)
val sessionResetImpl = SessionResetImplementation(this)
MentionsManager.configureIfNeeded(userPublicKey, threadDB, userDB)
SessionMetaProtocol.configureIfNeeded(apiDB, userPublicKey)
org.whispersystems.signalservice.loki.protocol.multidevice.MultiDeviceProtocol.configureIfNeeded(apiDB)

View File

@ -73,7 +73,7 @@ class SettingsActivity : PassphraseRequiredActionBarActivity() {
showQRCodeButton.setOnClickListener { showQRCode() }
glide = GlideApp.with(this)
profilePictureView.glide = glide
profilePictureView.hexEncodedPublicKey = hexEncodedPublicKey
profilePictureView.publicKey = hexEncodedPublicKey
profilePictureView.isLarge = true
profilePictureView.update()
profilePictureView.setOnClickListener { showEditProfilePictureUI() }

View File

@ -47,7 +47,7 @@ class BackgroundPollWorker : PersistentAlarmManagerListener() {
}
val openGroups = DatabaseFactory.getLokiThreadDatabase(context).getAllPublicChats().map { it.value }
for (openGroup in openGroups) {
val poller = LokiPublicChatPoller(context, openGroup)
val poller = PublicChatPoller(context, openGroup)
poller.stop()
poller.pollForNewMessages()
}

View File

@ -14,9 +14,9 @@ import org.thoughtcrime.securesms.util.TextSecurePreferences
import org.thoughtcrime.securesms.util.Util
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 val pollers = mutableMapOf<Long, LokiPublicChatPoller>()
private val pollers = mutableMapOf<Long, PublicChatPoller>()
private val observers = mutableMapOf<Long, ContentObserver>()
private var isPolling = false
@ -24,7 +24,7 @@ class LokiPublicChatManager(private val context: Context) {
var areAllCaughtUp = true
refreshChatsAndPollers()
for ((threadID, chat) in chats) {
val poller = pollers[threadID] ?: LokiPublicChatPoller(context, chat)
val poller = pollers[threadID] ?: PublicChatPoller(context, chat)
areAllCaughtUp = areAllCaughtUp && poller.isCaughtUp
}
return areAllCaughtUp
@ -33,7 +33,7 @@ class LokiPublicChatManager(private val context: Context) {
public fun markAllAsNotCaughtUp() {
refreshChatsAndPollers()
for ((threadID, chat) in chats) {
val poller = pollers[threadID] ?: LokiPublicChatPoller(context, chat)
val poller = pollers[threadID] ?: PublicChatPoller(context, chat)
poller.isCaughtUp = false
}
}
@ -42,7 +42,7 @@ class LokiPublicChatManager(private val context: Context) {
refreshChatsAndPollers()
for ((threadId, chat) in chats) {
val poller = pollers[threadId] ?: LokiPublicChatPoller(context, chat)
val poller = pollers[threadId] ?: PublicChatPoller(context, chat)
poller.startIfNeeded()
listenToThreadDeletion(threadId)
if (!pollers.containsKey(threadId)) { pollers[threadId] = poller }

View File

@ -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.PublicChatMessage
import org.whispersystems.signalservice.loki.protocol.multidevice.MultiDeviceProtocol
import org.whispersystems.signalservice.loki.protocol.todo.LokiThreadFriendRequestStatus
import java.security.MessageDigest
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 var hasStarted = false
public var isCaughtUp = false
@ -182,13 +181,6 @@ class LokiPublicChatPoller(private val context: Context, private val group: Publ
database.setProfileKey(senderAsRecipient, profileKey)
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) {

View File

@ -11,12 +11,11 @@ import org.thoughtcrime.securesms.loki.utilities.getInt
import org.thoughtcrime.securesms.loki.utilities.getString
import org.thoughtcrime.securesms.loki.utilities.insertOrUpdate
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 {
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 errorMessageTable = "loki_error_message_database"
private val messageID = "message_id"
@ -24,7 +23,7 @@ class LokiMessageDatabase(context: Context, helper: SQLCipherOpenHelper) : Datab
private val friendRequestStatus = "friend_request_status"
private val threadID = "thread_id"
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 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? {
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)
}?.toLong()
}
fun getMessageID(serverID: Long): Long? {
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)
}?.toLong()
}
@ -53,7 +52,7 @@ class LokiMessageDatabase(context: Context, helper: SQLCipherOpenHelper) : Datab
val contentValues = ContentValues(2)
contentValues.put(Companion.messageID, messageID)
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 {
@ -71,32 +70,6 @@ class LokiMessageDatabase(context: Context, helper: SQLCipherOpenHelper) : Datab
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? {
val database = databaseHelper.readableDatabase
return database.get(errorMessageTable, "${Companion.messageID} = ?", arrayOf( messageID.toString() )) { cursor ->

View File

@ -15,21 +15,18 @@ import org.whispersystems.libsignal.loki.SessionResetStatus
import org.whispersystems.signalservice.internal.util.JsonUtil
import org.whispersystems.signalservice.loki.api.opengroups.PublicChat
import org.whispersystems.signalservice.loki.database.LokiThreadDatabaseProtocol
import org.whispersystems.signalservice.loki.protocol.todo.LokiThreadFriendRequestStatus
import org.whispersystems.signalservice.loki.utilities.PublicKeyValidation
class LokiThreadDatabase(context: Context, helper: SQLCipherOpenHelper) : Database(context, helper), LokiThreadDatabaseProtocol {
var delegate: LokiThreadDatabaseDelegate? = null
companion object {
private val friendRequestTable = "loki_thread_friend_request_database"
private val sessionResetTable = "loki_thread_session_reset_database"
val publicChatTable = "loki_public_chat_database"
val threadID = "thread_id"
private val friendRequestStatus = "friend_request_status"
private val sessionResetStatus = "session_reset_status"
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 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)
}
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 {
val threadID = getThreadID(hexEncodedPublicKey)
val database = databaseHelper.readableDatabase

View File

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

View File

@ -15,10 +15,10 @@ sealed class ContactSelectionListItem {
class ContactSelectionListLoader(context: Context, val mode: Int, val filter: String?) : AsyncLoader<List<ContactSelectionListItem>>(context) {
object DisplayMode {
const val FLAG_FRIENDS = 1
const val FLAG_CONTACTS = 1
const val FLAG_CLOSED_GROUPS = 1 shl 1
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 {
@ -39,15 +39,15 @@ class ContactSelectionListLoader(context: Context, val mode: Int, val filter: St
if (isFlagSet(DisplayMode.FLAG_OPEN_GROUPS)) {
list.addAll(getOpenGroups(contacts))
}
if (isFlagSet(DisplayMode.FLAG_FRIENDS)) {
list.addAll(getFriends(contacts))
if (isFlagSet(DisplayMode.FLAG_CONTACTS)) {
list.addAll(getContacts(contacts))
}
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)) {
!it.recipient.isGroupRecipient && it.isFriend && !it.isOurDevice && !it.isSlave
!it.recipient.isGroupRecipient && !it.isOurDevice && !it.isSlave
}
}

View File

@ -10,10 +10,7 @@ class EphemeralMessage private constructor(val data: Map<*, *>) {
fun create(publicKey: String) = EphemeralMessage(mapOf( "recipient" to publicKey ))
@JvmStatic
fun createUnlinkingRequest(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 ))
fun createDeviceUnlinkingRequest(publicKey: String) = EphemeralMessage(mapOf( "recipient" to publicKey, "unpairingRequest" to true ))
@JvmStatic
fun createSessionRequest(publicKey: String) = EphemeralMessage(mapOf( "recipient" to publicKey, "friendRequest" to true, "sessionRequest" to true ))

View File

@ -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)
}
}

View File

@ -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.DeviceLinkingSession
import org.whispersystems.signalservice.loki.protocol.multidevice.MultiDeviceProtocol
import org.whispersystems.signalservice.loki.protocol.todo.LokiThreadFriendRequestStatus
import org.whispersystems.signalservice.loki.utilities.retryIfNeeded
object MultiDeviceProtocol {
@ -40,36 +39,6 @@ object MultiDeviceProtocol {
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) {
val jobManager = ApplicationContext.getInstance(context).jobManager
val isMultiDeviceRequired = !recipient.address.isOpenGroup
@ -82,7 +51,12 @@ object MultiDeviceProtocol {
val publicKey = recipient.address.serialize()
FileServerAPI.shared.getDeviceLinks(publicKey).success {
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")
when (messageType) {
MessageType.Text -> jobManager.startChain(jobs).enqueue()

View File

@ -27,8 +27,8 @@ object SessionManagementProtocol {
val smsDB = DatabaseFactory.getSmsDatabase(context)
val devices = lokiThreadDB.getSessionRestoreDevices(threadID)
for (device in devices) {
val sessionRestorationRequest = EphemeralMessage.createSessionRestorationRequest(recipient.address.serialize())
ApplicationContext.getInstance(context).jobManager.add(PushEphemeralMessageSendJob(sessionRestorationRequest))
val sessionRequest = EphemeralMessage.createSessionRequest(recipient.address.serialize())
ApplicationContext.getInstance(context).jobManager.add(PushEphemeralMessageSendJob(sessionRequest))
}
val infoMessage = OutgoingTextMessage(recipient, "", 0, 0)
val infoMessageID = smsDB.insertMessageOutbox(threadID, infoMessage, false, System.currentTimeMillis(), null)

View File

@ -11,7 +11,6 @@ import org.thoughtcrime.securesms.util.TextSecurePreferences
import org.whispersystems.signalservice.api.messages.SignalServiceContent
import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage
import org.whispersystems.signalservice.loki.protocol.multidevice.MultiDeviceProtocol
import org.whispersystems.signalservice.loki.protocol.todo.LokiThreadFriendRequestStatus
import java.security.MessageDigest
object SessionMetaProtocol {
@ -75,31 +74,23 @@ object SessionMetaProtocol {
* Should be invoked for the recipient's master device.
*/
@JvmStatic
fun canUserReplyToNotification(recipient: Recipient, context: Context): Boolean {
val isGroup = recipient.isGroupRecipient
if (isGroup) { return !recipient.address.isRSSFeed }
val threadID = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipient)
return DatabaseFactory.getLokiThreadDatabase(context).getFriendRequestStatus(threadID) == LokiThreadFriendRequestStatus.FRIENDS
fun canUserReplyToNotification(recipient: Recipient): Boolean {
return !recipient.address.isRSSFeed
}
/**
* Should be invoked for the recipient's master device.
*/
@JvmStatic
fun shouldSendReadReceipt(address: Address, context: Context): Boolean {
if (address.isGroup) { return false }
val recipient = Recipient.from(context, address,false)
val threadID = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipient)
return DatabaseFactory.getLokiThreadDatabase(context).getFriendRequestStatus(threadID) == LokiThreadFriendRequestStatus.FRIENDS
fun shouldSendReadReceipt(address: Address): Boolean {
return !address.isGroup
}
/**
* Should be invoked for the recipient's master device.
*/
@JvmStatic
fun shouldSendTypingIndicator(recipient: Recipient?, context: Context): Boolean {
if (recipient == null || recipient.isGroupRecipient) { return false }
val threadID = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipient)
return DatabaseFactory.getLokiThreadDatabase(context).getFriendRequestStatus(threadID) == LokiThreadFriendRequestStatus.FRIENDS
fun shouldSendTypingIndicator(address: Address): Boolean {
return !address.isGroup
}
}

View File

@ -7,7 +7,7 @@ import org.whispersystems.libsignal.loki.SessionResetProtocol
import org.whispersystems.libsignal.loki.SessionResetStatus
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 {
return DatabaseFactory.getLokiThreadDatabase(context).getSessionResetStatus(publicKey)

View File

@ -24,8 +24,6 @@ import org.whispersystems.signalservice.api.messages.multidevice.DeviceContactsI
import org.whispersystems.signalservice.api.messages.multidevice.DeviceGroupsInputStream
import org.whispersystems.signalservice.loki.api.opengroups.PublicChat
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 java.util.*
@ -67,9 +65,7 @@ object SyncMessagesProtocol {
if (!PublicKeyValidation.isValid(address.serialize())) { return false }
if (address.serialize() == TextSecurePreferences.getMasterHexEncodedPublicKey(context)) { return false }
if (address.serialize() == TextSecurePreferences.getLocalNumber(context)) { return false }
val threadID = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(Recipient.from(context, address, false))
val isFriend = DatabaseFactory.getLokiThreadDatabase(context).getFriendRequestStatus(threadID) == LokiThreadFriendRequestStatus.FRIENDS
return isFriend
return true
}
@JvmStatic
@ -99,29 +95,9 @@ object SyncMessagesProtocol {
for (contactPublicKey in contactPublicKeys) {
if (contactPublicKey == userPublicKey || !PublicKeyValidation.isValid(contactPublicKey)) { return }
val recipient = recipient(context, contactPublicKey)
val threadID = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipient)
val lokiThreadDB = DatabaseFactory.getLokiThreadDatabase(context)
val threadFRStatus = lokiThreadDB.getFriendRequestStatus(threadID)
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
}
}
val applicationContext = context.applicationContext as ApplicationContext
applicationContext.sendSessionRequestIfNeeded(contactPublicKey)
// TODO: Make the thread visible
}
}
@ -136,13 +112,13 @@ object SyncMessagesProtocol {
val closedGroups = closedGroupsInputStream.readAll()
for (closedGroup in closedGroups) {
val signalServiceGroup = SignalServiceGroup(
SignalServiceGroup.Type.UPDATE,
closedGroup.id,
SignalServiceGroup.GroupType.SIGNAL,
closedGroup.name.orNull(),
closedGroup.members,
closedGroup.avatar.orNull(),
closedGroup.admins
SignalServiceGroup.Type.UPDATE,
closedGroup.id,
SignalServiceGroup.GroupType.SIGNAL,
closedGroup.name.orNull(),
closedGroup.members,
closedGroup.avatar.orNull(),
closedGroup.admins
)
val signalServiceDataMessage = SignalServiceDataMessage(content.timestamp, signalServiceGroup, null, null)
// This establishes sessions internally

View File

@ -5,11 +5,9 @@ import org.thoughtcrime.securesms.database.DatabaseFactory
import org.thoughtcrime.securesms.recipients.Recipient
import org.thoughtcrime.securesms.util.TextSecurePreferences
import org.whispersystems.signalservice.loki.protocol.multidevice.MultiDeviceProtocol
import org.whispersystems.signalservice.loki.protocol.todo.LokiThreadFriendRequestStatus
data class Contact(
val recipient: Recipient,
val isFriend: Boolean,
val isSlave: Boolean,
val isOurDevice: Boolean
) {
@ -31,10 +29,9 @@ object ContactUtilities {
@JvmStatic
fun getAllContacts(context: Context): Set<Contact> {
val threadDatabase = DatabaseFactory.getThreadDatabase(context)
val lokiThreadDatabase = DatabaseFactory.getLokiThreadDatabase(context)
val userHexEncodedPublicKey = TextSecurePreferences.getLocalNumber(context)
val userPublicKey = TextSecurePreferences.getLocalNumber(context)
val lokiAPIDatabase = DatabaseFactory.getLokiAPIDatabase(context)
val userDevices = MultiDeviceProtocol.shared.getAllLinkedDevices(userHexEncodedPublicKey)
val userDevices = MultiDeviceProtocol.shared.getAllLinkedDevices(userPublicKey)
val cursor = threadDatabase.conversationList
val result = mutableSetOf<Contact>()
threadDatabase.readerFor(cursor).use { reader ->
@ -43,13 +40,12 @@ object ContactUtilities {
val recipient = thread.recipient
val publicKey = recipient.address.serialize()
val isUserDevice = userDevices.contains(publicKey)
val isFriend = lokiThreadDatabase.getFriendRequestStatus(thread.threadId) == LokiThreadFriendRequestStatus.FRIENDS
var isSlave = false
if (!recipient.isGroupRecipient) {
val deviceLinks = lokiAPIDatabase.getDeviceLinks(publicKey)
isSlave = deviceLinks.find { it.slavePublicKey == publicKey } != null
}
result.add(Contact(recipient, isFriend, isSlave, isUserDevice))
result.add(Contact(recipient, isSlave, isUserDevice))
}
}
return result

View File

@ -8,11 +8,11 @@ import org.thoughtcrime.securesms.recipients.Recipient
fun getOpenGroupDisplayName(recipient: Recipient, threadRecipient: Recipient, context: Context): String {
val threadID = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(threadRecipient)
val publicChat = DatabaseFactory.getLokiThreadDatabase(context).getPublicChat(threadID)
val hexEncodedPublicKey = recipient.address.toString()
val publicKey = recipient.address.toString()
val displayName = if (publicChat != null) {
DatabaseFactory.getLokiUserDatabase(context).getServerDisplayName(publicChat.id, hexEncodedPublicKey)
DatabaseFactory.getLokiUserDatabase(context).getServerDisplayName(publicChat.id, publicKey)
} else {
DatabaseFactory.getLokiUserDatabase(context).getDisplayName(hexEncodedPublicKey)
DatabaseFactory.getLokiUserDatabase(context).getDisplayName(publicKey)
}
return displayName ?: hexEncodedPublicKey
return displayName ?: publicKey
}

View File

@ -22,7 +22,7 @@ object OpenGroupUtilities {
val application = ApplicationContext.getInstance(context)
val displayName = TextSecurePreferences.getProfileName(context)
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).removeLastDeletionServerID(channel, url)
lokiPublicChatAPI.getMessages(channel, url)

View File

@ -50,18 +50,18 @@ class ConversationView : LinearLayout {
unreadMessagesIndicatorView.visibility = if (thread.unreadCount > 0) View.VISIBLE else View.INVISIBLE
if (thread.recipient.isGroupRecipient) {
if ("Session Public Chat" == thread.recipient.name) {
profilePictureView.hexEncodedPublicKey = ""
profilePictureView.publicKey = ""
profilePictureView.isRSSFeed = true
} else {
val users = MentionsManager.shared.userPublicKeyCache[thread.threadId]?.toList() ?: listOf()
val randomUsers = users.sorted() // Sort to provide a level of stability
profilePictureView.hexEncodedPublicKey = randomUsers.getOrNull(0) ?: ""
profilePictureView.additionalHexEncodedPublicKey = randomUsers.getOrNull(1) ?: ""
profilePictureView.publicKey = randomUsers.getOrNull(0) ?: ""
profilePictureView.additionalPublicKey = randomUsers.getOrNull(1) ?: ""
profilePictureView.isRSSFeed = thread.recipient.name == "Loki News" || thread.recipient.name == "Session Updates"
}
} else {
profilePictureView.hexEncodedPublicKey = thread.recipient.address.toString()
profilePictureView.additionalHexEncodedPublicKey = null
profilePictureView.publicKey = thread.recipient.address.toString()
profilePictureView.additionalPublicKey = null
profilePictureView.isRSSFeed = false
}
profilePictureView.glide = glide

View File

@ -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

View File

@ -31,8 +31,8 @@ class MentionCandidateView(context: Context, attrs: AttributeSet?, defStyleAttr:
private fun update() {
displayNameTextView.text = mentionCandidate.displayName
profilePictureView.hexEncodedPublicKey = mentionCandidate.publicKey
profilePictureView.additionalHexEncodedPublicKey = null
profilePictureView.publicKey = mentionCandidate.publicKey
profilePictureView.additionalPublicKey = null
profilePictureView.isRSSFeed = false
profilePictureView.glide = glide!!
profilePictureView.update()

View File

@ -21,8 +21,8 @@ import org.thoughtcrime.securesms.util.TextSecurePreferences
class ProfilePictureView : RelativeLayout {
lateinit var glide: GlideRequests
var hexEncodedPublicKey: String? = null
var additionalHexEncodedPublicKey: String? = null
var publicKey: String? = null
var additionalPublicKey: String? = null
var isRSSFeed = false
var isLarge = false
@ -52,11 +52,11 @@ class ProfilePictureView : RelativeLayout {
// region Updating
fun update() {
val hexEncodedPublicKey = hexEncodedPublicKey ?: return
val additionalHexEncodedPublicKey = additionalHexEncodedPublicKey
doubleModeImageViewContainer.visibility = if (additionalHexEncodedPublicKey != null && !isRSSFeed) View.VISIBLE else View.INVISIBLE
singleModeImageViewContainer.visibility = if (additionalHexEncodedPublicKey == null && !isRSSFeed && !isLarge) View.VISIBLE else View.INVISIBLE
largeSingleModeImageViewContainer.visibility = if (additionalHexEncodedPublicKey == null && !isRSSFeed && isLarge) View.VISIBLE else View.INVISIBLE
val publicKey = publicKey ?: return
val additionalPublicKey = additionalPublicKey
doubleModeImageViewContainer.visibility = if (additionalPublicKey != null && !isRSSFeed) View.VISIBLE else View.INVISIBLE
singleModeImageViewContainer.visibility = if (additionalPublicKey == 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
fun setProfilePictureIfNeeded(imageView: ImageView, hexEncodedPublicKey: String, @DimenRes sizeID: Int) {
glide.clear(imageView)
@ -76,10 +76,10 @@ class ProfilePictureView : RelativeLayout {
imageView.setImageDrawable(null)
}
}
setProfilePictureIfNeeded(doubleModeImageView1, hexEncodedPublicKey, R.dimen.small_profile_picture_size)
setProfilePictureIfNeeded(doubleModeImageView2, additionalHexEncodedPublicKey ?: "", R.dimen.small_profile_picture_size)
setProfilePictureIfNeeded(singleModeImageView, hexEncodedPublicKey, R.dimen.medium_profile_picture_size)
setProfilePictureIfNeeded(largeSingleModeImageView, hexEncodedPublicKey, R.dimen.large_profile_picture_size)
setProfilePictureIfNeeded(doubleModeImageView1, publicKey, R.dimen.small_profile_picture_size)
setProfilePictureIfNeeded(doubleModeImageView2, additionalPublicKey ?: "", R.dimen.small_profile_picture_size)
setProfilePictureIfNeeded(singleModeImageView, publicKey, R.dimen.medium_profile_picture_size)
setProfilePictureIfNeeded(largeSingleModeImageView, publicKey, R.dimen.large_profile_picture_size)
}
// endregion
}

View File

@ -48,20 +48,20 @@ class UserView : LinearLayout {
val address = user.address.serialize()
if (user.isGroupRecipient) {
if ("Session Public Chat" == user.name || user.address.isRSSFeed) {
profilePictureView.hexEncodedPublicKey = ""
profilePictureView.additionalHexEncodedPublicKey = null
profilePictureView.publicKey = ""
profilePictureView.additionalPublicKey = null
profilePictureView.isRSSFeed = true
} else {
val threadID = GroupManager.getThreadIDFromGroupID(address, context)
val users = MentionsManager.shared.userPublicKeyCache[threadID]?.toList() ?: listOf()
val randomUsers = users.sorted() // Sort to provide a level of stability
profilePictureView.hexEncodedPublicKey = randomUsers.getOrNull(0) ?: ""
profilePictureView.additionalHexEncodedPublicKey = randomUsers.getOrNull(1) ?: ""
profilePictureView.publicKey = randomUsers.getOrNull(0) ?: ""
profilePictureView.additionalPublicKey = randomUsers.getOrNull(1) ?: ""
profilePictureView.isRSSFeed = false
}
} else {
profilePictureView.hexEncodedPublicKey = address
profilePictureView.additionalHexEncodedPublicKey = null
profilePictureView.publicKey = address
profilePictureView.additionalPublicKey = null
profilePictureView.isRSSFeed = false
}
profilePictureView.glide = glide

View File

@ -23,7 +23,6 @@ public class OutgoingMediaMessage {
private final int distributionType;
private final int subscriptionId;
private final long expiresIn;
public boolean isFriendRequest = false;
private final QuoteModel outgoingQuote;
private final List<NetworkFailure> networkFailures = new LinkedList<>();

View File

@ -325,7 +325,7 @@ public class DefaultMessageNotifier implements MessageNotifier {
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 remoteReplyIntent = canReply ? notificationState.getRemoteReplyIntent(context, recipient, replyMethod) : null;

View File

@ -93,7 +93,7 @@ public class MarkReadReceiver extends BroadcastReceiver {
for (Address address : addressMap.keySet()) {
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
if (!SessionMetaProtocol.shouldSendReadReceipt(address, context)) { continue; }
if (!SessionMetaProtocol.shouldSendReadReceipt(address)) { continue; }
// Loki - Take into account multi device
Set<String> linkedDevices = MultiDeviceProtocol.shared.getAllLinkedDevices(address.serialize());
for (String device : linkedDevices) {

View File

@ -7,7 +7,7 @@ import androidx.annotation.MainThread;
import androidx.annotation.NonNull;
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.util.Debouncer;
import org.whispersystems.signalservice.loki.api.Poller;
@ -41,14 +41,14 @@ public class OptimizedMessageNotifier implements MessageNotifier {
@Override
public void updateNotification(@NonNull Context context) {
Poller lokiPoller = ApplicationContext.getInstance(context).lokiPoller;
LokiPublicChatManager lokiPublicChatManager = ApplicationContext.getInstance(context).lokiPublicChatManager;
PublicChatManager publicChatManager = ApplicationContext.getInstance(context).publicChatManager;
boolean isCaughtUp = true;
if (lokiPoller != null) {
isCaughtUp = isCaughtUp && lokiPoller.isCaughtUp();
}
if (lokiPublicChatManager != null) {
isCaughtUp = isCaughtUp && lokiPublicChatManager.areAllCaughtUp();
if (publicChatManager != null) {
isCaughtUp = isCaughtUp && publicChatManager.areAllCaughtUp();
}
if (isCaughtUp) {
@ -61,14 +61,14 @@ public class OptimizedMessageNotifier implements MessageNotifier {
@Override
public void updateNotification(@NonNull Context context, long threadId) {
Poller lokiPoller = ApplicationContext.getInstance(context).lokiPoller;
LokiPublicChatManager lokiPublicChatManager = ApplicationContext.getInstance(context).lokiPublicChatManager;
PublicChatManager publicChatManager = ApplicationContext.getInstance(context).publicChatManager;
boolean isCaughtUp = true;
if (lokiPoller != null) {
isCaughtUp = isCaughtUp && lokiPoller.isCaughtUp();
}
if (lokiPublicChatManager != null) {
isCaughtUp = isCaughtUp && lokiPublicChatManager.areAllCaughtUp();
if (publicChatManager != null) {
isCaughtUp = isCaughtUp && publicChatManager.areAllCaughtUp();
}
if (isCaughtUp) {
@ -81,14 +81,14 @@ public class OptimizedMessageNotifier implements MessageNotifier {
@Override
public void updateNotification(@NonNull Context context, long threadId, boolean signal) {
Poller lokiPoller = ApplicationContext.getInstance(context).lokiPoller;
LokiPublicChatManager lokiPublicChatManager = ApplicationContext.getInstance(context).lokiPublicChatManager;
PublicChatManager publicChatManager = ApplicationContext.getInstance(context).publicChatManager;
boolean isCaughtUp = true;
if (lokiPoller != null) {
isCaughtUp = isCaughtUp && lokiPoller.isCaughtUp();
}
if (lokiPublicChatManager != null) {
isCaughtUp = isCaughtUp && lokiPublicChatManager.areAllCaughtUp();
if (publicChatManager != null) {
isCaughtUp = isCaughtUp && publicChatManager.areAllCaughtUp();
}
if (isCaughtUp) {
@ -101,14 +101,14 @@ public class OptimizedMessageNotifier implements MessageNotifier {
@Override
public void updateNotification(@android.support.annotation.NonNull Context context, boolean signal, int reminderCount) {
Poller lokiPoller = ApplicationContext.getInstance(context).lokiPoller;
LokiPublicChatManager lokiPublicChatManager = ApplicationContext.getInstance(context).lokiPublicChatManager;
PublicChatManager publicChatManager = ApplicationContext.getInstance(context).publicChatManager;
boolean isCaughtUp = true;
if (lokiPoller != null) {
isCaughtUp = isCaughtUp && lokiPoller.isCaughtUp();
}
if (lokiPublicChatManager != null) {
isCaughtUp = isCaughtUp && lokiPublicChatManager.areAllCaughtUp();
if (publicChatManager != null) {
isCaughtUp = isCaughtUp && publicChatManager.areAllCaughtUp();
}
if (isCaughtUp) {

View File

@ -38,7 +38,6 @@ import org.thoughtcrime.securesms.jobs.MmsSendJob;
import org.thoughtcrime.securesms.jobs.PushGroupSendJob;
import org.thoughtcrime.securesms.jobs.SmsSendJob;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.loki.protocol.FriendRequestProtocol;
import org.thoughtcrime.securesms.loki.protocol.MultiDeviceProtocol;
import org.thoughtcrime.securesms.mms.MmsException;
import org.thoughtcrime.securesms.mms.OutgoingMediaMessage;
@ -76,11 +75,6 @@ public class MessageSender {
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());
return allocatedThreadId;
@ -107,11 +101,6 @@ public class MessageSender {
Recipient recipient = message.getRecipient();
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());
return allocatedThreadId;
} catch (MmsException e) {

View File

@ -9,7 +9,6 @@ public class OutgoingTextMessage {
private final String message;
private final int subscriptionId;
private final long expiresIn;
public boolean isFriendRequest = false;
public OutgoingTextMessage(Recipient recipient, String message, int subscriptionId) {
this(recipient, message, 0, subscriptionId);